geoblacklight_admin 0.0.1

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 (346) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +18 -0
  3. data/.gitignore +75 -0
  4. data/.standard.yml +4 -0
  5. data/Gemfile +59 -0
  6. data/LICENSE +21 -0
  7. data/README.md +84 -0
  8. data/Rakefile +72 -0
  9. data/app/assets/images/.keep +0 -0
  10. data/app/assets/images/aerial_photo.jpg +0 -0
  11. data/app/assets/images/archive-solid.svg +1 -0
  12. data/app/assets/images/bookmark-regular.svg +1 -0
  13. data/app/assets/images/bookmark-solid.svg +1 -0
  14. data/app/assets/images/btaa-logo.jpg +0 -0
  15. data/app/assets/images/cloud-download-alt-solid.svg +1 -0
  16. data/app/assets/images/file-import-solid.svg +1 -0
  17. data/app/assets/images/trash-alt-solid.svg +1 -0
  18. data/app/assets/javascripts/geoblacklight_admin/chosen.js +4 -0
  19. data/app/assets/javascripts/geoblacklight_admin/date_range_picker.js +173 -0
  20. data/app/assets/javascripts/geoblacklight_admin/datepicker.js +22 -0
  21. data/app/assets/javascripts/geoblacklight_admin/elements.js +38 -0
  22. data/app/assets/javascripts/geoblacklight_admin/exports.js +3 -0
  23. data/app/assets/javascripts/geoblacklight_admin/fields.js +11 -0
  24. data/app/assets/javascripts/geoblacklight_admin/geoblacklight_admin.js +2 -0
  25. data/app/assets/javascripts/geoblacklight_admin/inputmask.js +4 -0
  26. data/app/assets/javascripts/geoblacklight_admin/locale.js +5 -0
  27. data/app/assets/javascripts/geoblacklight_admin/sortable.js +2544 -0
  28. data/app/assets/javascripts/geoblacklight_admin/tooltips.js +3 -0
  29. data/app/assets/javascripts/geoblacklight_admin/truncate.js +4 -0
  30. data/app/assets/javascripts/geoblacklight_admin.js +40 -0
  31. data/app/assets/stylesheets/geoblacklight_admin/_core.scss +47 -0
  32. data/app/assets/stylesheets/geoblacklight_admin/modules/_autocomplete.scss +32 -0
  33. data/app/assets/stylesheets/geoblacklight_admin/modules/_blazer.scss +3 -0
  34. data/app/assets/stylesheets/geoblacklight_admin/modules/_code.scss +3 -0
  35. data/app/assets/stylesheets/geoblacklight_admin/modules/_datepicker.scss +477 -0
  36. data/app/assets/stylesheets/geoblacklight_admin/modules/_elements.scss +3 -0
  37. data/app/assets/stylesheets/geoblacklight_admin/modules/_forms.scss +28 -0
  38. data/app/assets/stylesheets/geoblacklight_admin/modules/_icons.scss +15 -0
  39. data/app/assets/stylesheets/geoblacklight_admin/modules/_nav.scss +9 -0
  40. data/app/assets/stylesheets/geoblacklight_admin/modules/_tables.scss +4 -0
  41. data/app/assets/stylesheets/geoblacklight_admin/modules/_toasts.scss +7 -0
  42. data/app/assets/stylesheets/geoblacklight_admin/modules/_visibility.scss +3 -0
  43. data/app/assets/stylesheets/geoblacklight_admin/settings/_variables.scss +1 -0
  44. data/app/channels/export_channel.rb +12 -0
  45. data/app/controllers/admin/admin_controller.rb +16 -0
  46. data/app/controllers/admin/advanced_search_controller.rb +365 -0
  47. data/app/controllers/admin/api_controller.rb +386 -0
  48. data/app/controllers/admin/bookmarks_controller.rb +68 -0
  49. data/app/controllers/admin/bulk_actions_controller.rb +94 -0
  50. data/app/controllers/admin/concerns/.keep +0 -0
  51. data/app/controllers/admin/concerns/upload_util.rb +8 -0
  52. data/app/controllers/admin/document_accesses_controller.rb +125 -0
  53. data/app/controllers/admin/document_assets_controller.rb +198 -0
  54. data/app/controllers/admin/document_downloads_controller.rb +127 -0
  55. data/app/controllers/admin/documents_controller.rb +219 -0
  56. data/app/controllers/admin/elements_controller.rb +81 -0
  57. data/app/controllers/admin/form_elements_controller.rb +81 -0
  58. data/app/controllers/admin/ids_controller.rb +379 -0
  59. data/app/controllers/admin/import_documents_controller.rb +18 -0
  60. data/app/controllers/admin/imports_controller.rb +105 -0
  61. data/app/controllers/admin/mappings_controller.rb +95 -0
  62. data/app/controllers/admin/notifications_controller.rb +51 -0
  63. data/app/controllers/admin/search_controller.rb +10 -0
  64. data/app/controllers/admin/users_controller.rb +10 -0
  65. data/app/helpers/bulk_actions_helper.rb +9 -0
  66. data/app/helpers/document_helper.rb +60 -0
  67. data/app/helpers/form_input_helper.rb +73 -0
  68. data/app/helpers/geoblacklight_admin_helper.rb +118 -0
  69. data/app/helpers/import_documents_helper.rb +5 -0
  70. data/app/helpers/mappings_helper.rb +27 -0
  71. data/app/indexers/document_indexer.rb +34 -0
  72. data/app/jobs/bulk_action_revert_document_job.rb +49 -0
  73. data/app/jobs/bulk_action_revert_job.rb +25 -0
  74. data/app/jobs/bulk_action_run_document_job.rb +42 -0
  75. data/app/jobs/bulk_action_run_job.rb +27 -0
  76. data/app/jobs/export_job.rb +72 -0
  77. data/app/jobs/export_json_job.rb +120 -0
  78. data/app/jobs/import_document_job.rb +25 -0
  79. data/app/jobs/import_run_job.rb +33 -0
  80. data/app/models/active_storage_attachment.rb +5 -0
  81. data/app/models/active_storage_blob.rb +5 -0
  82. data/app/models/api_search_builder.rb +12 -0
  83. data/app/models/application_record.rb +6 -0
  84. data/app/models/blacklight_api.rb +93 -0
  85. data/app/models/blacklight_api_facets.rb +15 -0
  86. data/app/models/blacklight_api_ids.rb +103 -0
  87. data/app/models/bookmark.rb +17 -0
  88. data/app/models/bulk_action.rb +88 -0
  89. data/app/models/bulk_action_document.rb +22 -0
  90. data/app/models/bulk_action_document_state_machine.rb +16 -0
  91. data/app/models/bulk_action_document_transition.rb +19 -0
  92. data/app/models/bulk_action_state_machine.rb +16 -0
  93. data/app/models/bulk_action_transition.rb +26 -0
  94. data/app/models/concerns/.keep +0 -0
  95. data/app/models/document/bbox_validator.rb +70 -0
  96. data/app/models/document/controlled_lists.rb +104 -0
  97. data/app/models/document/date_range_validator.rb +63 -0
  98. data/app/models/document/geom_validator.rb +117 -0
  99. data/app/models/document/reference.rb +107 -0
  100. data/app/models/document.rb +264 -0
  101. data/app/models/document_access.rb +35 -0
  102. data/app/models/document_download.rb +35 -0
  103. data/app/models/document_state_machine.rb +14 -0
  104. data/app/models/document_transition.rb +26 -0
  105. data/app/models/element.rb +90 -0
  106. data/app/models/form_control.rb +2 -0
  107. data/app/models/form_element.rb +19 -0
  108. data/app/models/form_feature.rb +2 -0
  109. data/app/models/form_group.rb +2 -0
  110. data/app/models/form_header.rb +2 -0
  111. data/app/models/geoblacklight_admin/field_mappings_btaa_aardvark.rb +379 -0
  112. data/app/models/geoblacklight_admin/field_mappings_gblv1.rb +344 -0
  113. data/app/models/geoblacklight_admin/iso_language_codes.rb +515 -0
  114. data/app/models/geoblacklight_admin/schema.rb +194 -0
  115. data/app/models/geoblacklight_admin.rb +3 -0
  116. data/app/models/import/csv_duplicates_validator.rb +36 -0
  117. data/app/models/import/csv_header_validator.rb +24 -0
  118. data/app/models/import.rb +186 -0
  119. data/app/models/import_btaa.rb +91 -0
  120. data/app/models/import_btaa_aardvark.rb +109 -0
  121. data/app/models/import_document.rb +34 -0
  122. data/app/models/import_document_state_machine.rb +12 -0
  123. data/app/models/import_document_transition.rb +19 -0
  124. data/app/models/import_gblv1.rb +92 -0
  125. data/app/models/import_state_machine.rb +16 -0
  126. data/app/models/import_transition.rb +26 -0
  127. data/app/models/mapping.rb +10 -0
  128. data/app/models/notification.rb +9 -0
  129. data/app/models/user.rb +26 -0
  130. data/app/notifications/export_notification.rb +30 -0
  131. data/app/services/export_csv_document_access_links_service.rb +47 -0
  132. data/app/services/export_csv_document_downloads_service.rb +47 -0
  133. data/app/services/export_csv_service.rb +44 -0
  134. data/app/services/export_json_service.rb +35 -0
  135. data/app/services/zip_file_generator.rb +56 -0
  136. data/app/views/admin/advanced_search/facets.json.jbuilder +80 -0
  137. data/app/views/admin/advanced_search/index.json.jbuilder +90 -0
  138. data/app/views/admin/api/_field.json.jbuilder +10 -0
  139. data/app/views/admin/api/fetch.json.jbuilder +86 -0
  140. data/app/views/admin/api/index.json.jbuilder +90 -0
  141. data/app/views/admin/bookmarks/_bookmark.json.jbuilder +4 -0
  142. data/app/views/admin/bookmarks/create.js.erb +7 -0
  143. data/app/views/admin/bookmarks/destroy.js.erb +7 -0
  144. data/app/views/admin/bookmarks/index.html.erb +21 -0
  145. data/app/views/admin/bookmarks/index.json.jbuilder +3 -0
  146. data/app/views/admin/bulk_actions/_bulk_action.json.jbuilder +4 -0
  147. data/app/views/admin/bulk_actions/_form.html.erb +17 -0
  148. data/app/views/admin/bulk_actions/edit.html.erb +6 -0
  149. data/app/views/admin/bulk_actions/index.html.erb +54 -0
  150. data/app/views/admin/bulk_actions/index.json.jbuilder +3 -0
  151. data/app/views/admin/bulk_actions/new.html.erb +5 -0
  152. data/app/views/admin/bulk_actions/show.html.erb +100 -0
  153. data/app/views/admin/bulk_actions/show.json.jbuilder +3 -0
  154. data/app/views/admin/devise/confirmations/new.html.erb +16 -0
  155. data/app/views/admin/devise/invitations/edit.html.erb +15 -0
  156. data/app/views/admin/devise/invitations/new.html.erb +15 -0
  157. data/app/views/admin/devise/mailer/invitation_instructions.html.erb +11 -0
  158. data/app/views/admin/devise/mailer/invitation_instructions.text.erb +11 -0
  159. data/app/views/admin/devise/passwords/edit.html.erb +26 -0
  160. data/app/views/admin/devise/passwords/new.html.erb +16 -0
  161. data/app/views/admin/devise/registrations/edit.html.erb +35 -0
  162. data/app/views/admin/devise/registrations/new.html.erb +30 -0
  163. data/app/views/admin/devise/sessions/new.html.erb +28 -0
  164. data/app/views/admin/devise/shared/_links.html.erb +27 -0
  165. data/app/views/admin/devise/unlocks/new.html.erb +16 -0
  166. data/app/views/admin/document_accesses/_document_access.json.jbuilder +4 -0
  167. data/app/views/admin/document_accesses/_form.html.erb +17 -0
  168. data/app/views/admin/document_accesses/destroy_all.html.erb +70 -0
  169. data/app/views/admin/document_accesses/edit.html.erb +5 -0
  170. data/app/views/admin/document_accesses/import.html.erb +70 -0
  171. data/app/views/admin/document_accesses/index.html.erb +74 -0
  172. data/app/views/admin/document_accesses/index.json.jbuilder +3 -0
  173. data/app/views/admin/document_accesses/new.html.erb +6 -0
  174. data/app/views/admin/document_accesses/show.html.erb +19 -0
  175. data/app/views/admin/document_accesses/show.json.jbuilder +3 -0
  176. data/app/views/admin/document_assets/display_attach_form.html.erb +44 -0
  177. data/app/views/admin/document_assets/index.html.erb +65 -0
  178. data/app/views/admin/document_downloads/_document_download.json.jbuilder +4 -0
  179. data/app/views/admin/document_downloads/_form.html.erb +15 -0
  180. data/app/views/admin/document_downloads/destroy_all.html.erb +70 -0
  181. data/app/views/admin/document_downloads/edit.html.erb +6 -0
  182. data/app/views/admin/document_downloads/import.html.erb +74 -0
  183. data/app/views/admin/document_downloads/index.html.erb +70 -0
  184. data/app/views/admin/document_downloads/index.json.jbuilder +3 -0
  185. data/app/views/admin/document_downloads/new.html.erb +5 -0
  186. data/app/views/admin/document_downloads/show.html.erb +24 -0
  187. data/app/views/admin/document_downloads/show.json.jbuilder +3 -0
  188. data/app/views/admin/documents/_document.html.erb +29 -0
  189. data/app/views/admin/documents/_document_bookmark.html.erb +17 -0
  190. data/app/views/admin/documents/_document_fields.html.erb +24 -0
  191. data/app/views/admin/documents/_form.html.erb +49 -0
  192. data/app/views/admin/documents/_form_control.html.erb +86 -0
  193. data/app/views/admin/documents/_form_group.html.erb +1 -0
  194. data/app/views/admin/documents/_form_header.html.erb +1 -0
  195. data/app/views/admin/documents/_form_nav.html.erb +21 -0
  196. data/app/views/admin/documents/_json_aardvark.jbuilder +47 -0
  197. data/app/views/admin/documents/_json_btaa_aardvark.jbuilder +16 -0
  198. data/app/views/admin/documents/_json_gbl_v1.jbuilder +32 -0
  199. data/app/views/admin/documents/_result_facets.html.erb +35 -0
  200. data/app/views/admin/documents/_result_pagination.html.erb +21 -0
  201. data/app/views/admin/documents/_result_selected_options.html.erb +54 -0
  202. data/app/views/admin/documents/_result_selection_options.html.erb +10 -0
  203. data/app/views/admin/documents/_result_toggle.html.erb +13 -0
  204. data/app/views/admin/documents/edit.html.erb +7 -0
  205. data/app/views/admin/documents/features/_assets.html.erb +3 -0
  206. data/app/views/admin/documents/features/_institutional_access_links.html.erb +3 -0
  207. data/app/views/admin/documents/features/_multiple_download_links.html.erb +27 -0
  208. data/app/views/admin/documents/fetch.json_aardvark.jbuilder +9 -0
  209. data/app/views/admin/documents/fetch.json_btaa_aardvark.jbuilder +9 -0
  210. data/app/views/admin/documents/fetch.json_gbl_v1.jbuilder +9 -0
  211. data/app/views/admin/documents/index.html.erb +49 -0
  212. data/app/views/admin/documents/index.json_aardvark.jbuilder +9 -0
  213. data/app/views/admin/documents/index.json_btaa_aardvark.jbuilder +9 -0
  214. data/app/views/admin/documents/index.json_gbl_v1.jbuilder +9 -0
  215. data/app/views/admin/documents/show.json_aardvark.jbuilder +3 -0
  216. data/app/views/admin/documents/show.json_btaa_aardvark.jbuilder +3 -0
  217. data/app/views/admin/documents/show.json_gbl_v1.jbuilder +3 -0
  218. data/app/views/admin/documents/versions.html.erb +110 -0
  219. data/app/views/admin/elements/_element.json.jbuilder +2 -0
  220. data/app/views/admin/elements/_form.html.erb +45 -0
  221. data/app/views/admin/elements/edit.html.erb +6 -0
  222. data/app/views/admin/elements/index.html.erb +68 -0
  223. data/app/views/admin/elements/index.json.jbuilder +1 -0
  224. data/app/views/admin/elements/new.html.erb +5 -0
  225. data/app/views/admin/elements/show.html.erb +121 -0
  226. data/app/views/admin/elements/show.json.jbuilder +1 -0
  227. data/app/views/admin/form_elements/_form.html.erb +46 -0
  228. data/app/views/admin/form_elements/_form_element.json.jbuilder +2 -0
  229. data/app/views/admin/form_elements/edit.html.erb +6 -0
  230. data/app/views/admin/form_elements/index.html.erb +49 -0
  231. data/app/views/admin/form_elements/index.json.jbuilder +1 -0
  232. data/app/views/admin/form_elements/new.html.erb +5 -0
  233. data/app/views/admin/form_elements/show.html.erb +19 -0
  234. data/app/views/admin/form_elements/show.json.jbuilder +1 -0
  235. data/app/views/admin/ids/fetch.json.jbuilder +86 -0
  236. data/app/views/admin/ids/index.json.jbuilder +41 -0
  237. data/app/views/admin/import_documents/show.html.haml +20 -0
  238. data/app/views/admin/imports/_form.html.erb +27 -0
  239. data/app/views/admin/imports/_import.json.jbuilder +4 -0
  240. data/app/views/admin/imports/_show_failed_tab.html.erb +37 -0
  241. data/app/views/admin/imports/_show_success_tab.html.erb +31 -0
  242. data/app/views/admin/imports/edit.html.erb +8 -0
  243. data/app/views/admin/imports/index.html.erb +56 -0
  244. data/app/views/admin/imports/index.json.jbuilder +3 -0
  245. data/app/views/admin/imports/new.html.erb +7 -0
  246. data/app/views/admin/imports/show.html.erb +123 -0
  247. data/app/views/admin/imports/show.json.jbuilder +3 -0
  248. data/app/views/admin/layouts/application.html.erb +30 -0
  249. data/app/views/admin/layouts/blazer/application.html.erb +23 -0
  250. data/app/views/admin/layouts/mailer.html.erb +13 -0
  251. data/app/views/admin/layouts/mailer.text.erb +1 -0
  252. data/app/views/admin/mappings/_form.html.erb +17 -0
  253. data/app/views/admin/mappings/_mapping.json.jbuilder +4 -0
  254. data/app/views/admin/mappings/edit.html.erb +6 -0
  255. data/app/views/admin/mappings/index.html.erb +37 -0
  256. data/app/views/admin/mappings/index.json.jbuilder +3 -0
  257. data/app/views/admin/mappings/new.html.erb +5 -0
  258. data/app/views/admin/mappings/show.html.erb +27 -0
  259. data/app/views/admin/mappings/show.json.jbuilder +3 -0
  260. data/app/views/admin/notifications/_notification.html.haml +31 -0
  261. data/app/views/admin/notifications/index.html.erb +54 -0
  262. data/app/views/admin/notifications/update.js.erb +7 -0
  263. data/app/views/admin/search/index.html.erb +38 -0
  264. data/app/views/admin/shared/_flash_messages.html.erb +5 -0
  265. data/app/views/admin/shared/_footer.html.erb +56 -0
  266. data/app/views/admin/shared/_js_behaviors.html.erb +147 -0
  267. data/app/views/admin/shared/_navbar.html.erb +78 -0
  268. data/app/views/admin/shared/_navbar_blazer.html.erb +42 -0
  269. data/app/views/admin/shared/_schema_timestamp.html.erb +16 -0
  270. data/app/views/admin/shared/_toast.html.erb +13 -0
  271. data/app/views/admin/users/index.html.erb +21 -0
  272. data/config/authorities/formats.yml +25 -0
  273. data/config/authorities/languages.yml +50 -0
  274. data/config/authorities/resource_type.yml +82 -0
  275. data/config/blazer.yml +79 -0
  276. data/config/gbl_v1_schema.json +118 -0
  277. data/config/geomg_aardvark_schema.json +211 -0
  278. data/config/geomg_schema.json +123 -0
  279. data/config/locales/devise.en.yml +65 -0
  280. data/config/locales/devise_invitable.en.yml +31 -0
  281. data/config/locales/documents.en.yml +189 -0
  282. data/config/locales/en.yml +51 -0
  283. data/config/locales/geoblacklight.en.yml +178 -0
  284. data/config/locales/simple_form.en.yml +31 -0
  285. data/config/routes.rb +162 -0
  286. data/db/migrate/20230316183001_add_geoblacklight_admin.rb +399 -0
  287. data/db/seeds.rb +26 -0
  288. data/db/seeds_elements.csv +56 -0
  289. data/db/seeds_elements.numbers +0 -0
  290. data/db/seeds_form_elements.csv +71 -0
  291. data/db/seeds_form_elements.numbers +0 -0
  292. data/db/structure.sql +816 -0
  293. data/geoblacklight_admin.gemspec +67 -0
  294. data/lib/generators/geoblacklight_admin/config_generator.rb +336 -0
  295. data/lib/generators/geoblacklight_admin/example_docs_generator.rb +18 -0
  296. data/lib/generators/geoblacklight_admin/helpers_generator.rb +18 -0
  297. data/lib/generators/geoblacklight_admin/install_generator.rb +60 -0
  298. data/lib/generators/geoblacklight_admin/jobs_generator.rb +21 -0
  299. data/lib/generators/geoblacklight_admin/models_generator.rb +23 -0
  300. data/lib/generators/geoblacklight_admin/templates/.env.development.example +28 -0
  301. data/lib/generators/geoblacklight_admin/templates/.solr_wrapper.yml +7 -0
  302. data/lib/generators/geoblacklight_admin/templates/_user_util_links.html.erb +30 -0
  303. data/lib/generators/geoblacklight_admin/templates/config/database.yml +18 -0
  304. data/lib/generators/geoblacklight_admin/templates/config/geomg_aardvark_schema.json +211 -0
  305. data/lib/generators/geoblacklight_admin/templates/config/initializers/geoblacklight_admin.rb +25 -0
  306. data/lib/generators/geoblacklight_admin/templates/config/initializers/kithe.rb +31 -0
  307. data/lib/generators/geoblacklight_admin/templates/config/initializers/pagy.rb +158 -0
  308. data/lib/generators/geoblacklight_admin/templates/config/initializers/statesman.rb +7 -0
  309. data/lib/generators/geoblacklight_admin/templates/javascript/channels/consumer.js +6 -0
  310. data/lib/generators/geoblacklight_admin/templates/javascript/channels/export_channel.js +30 -0
  311. data/lib/generators/geoblacklight_admin/templates/javascript/channels/index.js +5 -0
  312. data/lib/generators/geoblacklight_admin/templates/javascript/controllers/application_controller.js +17 -0
  313. data/lib/generators/geoblacklight_admin/templates/javascript/controllers/document_controller.js +26 -0
  314. data/lib/generators/geoblacklight_admin/templates/javascript/controllers/index.js +10 -0
  315. data/lib/generators/geoblacklight_admin/templates/javascript/controllers/results_controller.js +310 -0
  316. data/lib/generators/geoblacklight_admin/templates/javascript/packs/application.js +23 -0
  317. data/lib/generators/geoblacklight_admin/templates/javascript/src/js/admin/qa_autocomplete.js +1134 -0
  318. data/lib/generators/geoblacklight_admin/templates/package.json +32 -0
  319. data/lib/generators/geoblacklight_admin/templates/solr/README-geoblacklight-solr-development.txt +3 -0
  320. data/lib/generators/geoblacklight_admin/templates/solr/conf/_rest_managed.json +3 -0
  321. data/lib/generators/geoblacklight_admin/templates/solr/conf/admin-extra.html +31 -0
  322. data/lib/generators/geoblacklight_admin/templates/solr/conf/core.properties +5 -0
  323. data/lib/generators/geoblacklight_admin/templates/solr/conf/elevate.xml +36 -0
  324. data/lib/generators/geoblacklight_admin/templates/solr/conf/mapping-ISOLatin1Accent.txt +246 -0
  325. data/lib/generators/geoblacklight_admin/templates/solr/conf/protwords.txt +21 -0
  326. data/lib/generators/geoblacklight_admin/templates/solr/conf/schema.xml +229 -0
  327. data/lib/generators/geoblacklight_admin/templates/solr/conf/scripts.conf +24 -0
  328. data/lib/generators/geoblacklight_admin/templates/solr/conf/solrconfig.xml +266 -0
  329. data/lib/generators/geoblacklight_admin/templates/solr/conf/spellings.txt +2 -0
  330. data/lib/generators/geoblacklight_admin/templates/solr/conf/stopwords.txt +58 -0
  331. data/lib/generators/geoblacklight_admin/templates/solr/conf/stopwords_en.txt +58 -0
  332. data/lib/generators/geoblacklight_admin/templates/solr/conf/synonyms.txt +43 -0
  333. data/lib/generators/geoblacklight_admin/templates/solr/conf/xslt/example.xsl +132 -0
  334. data/lib/generators/geoblacklight_admin/templates/solr/conf/xslt/example_atom.xsl +67 -0
  335. data/lib/generators/geoblacklight_admin/templates/solr/conf/xslt/example_rss.xsl +66 -0
  336. data/lib/generators/geoblacklight_admin/templates/solr/conf/xslt/luke.xsl +337 -0
  337. data/lib/generators/geoblacklight_admin/templates/solr/snapshots/.keep +0 -0
  338. data/lib/generators/geoblacklight_admin/views_generator.rb +19 -0
  339. data/lib/geoblacklight_admin/engine.rb +20 -0
  340. data/lib/geoblacklight_admin/version.rb +5 -0
  341. data/lib/geoblacklight_admin.rb +7 -0
  342. data/lib/tasks/.keep +0 -0
  343. data/lib/tasks/geoblacklight_admin.rake +209 -0
  344. data/spec/test_app_templates/lib/generators/test_app_generator.rb +35 -0
  345. data/template.rb +16 -0
  346. metadata +1037 -0
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # To deliver this notification:
4
+ #
5
+ # ExportNotification.with(post: @post).deliver_later(current_user)
6
+ # ExportNotification.with(post: @post).deliver(current_user)
7
+
8
+ # ExportNotification
9
+ class ExportNotification < Noticed::Base
10
+ # Add your delivery methods
11
+ #
12
+ deliver_by :database
13
+ # deliver_by :email, mailer: "UserMailer"
14
+ # deliver_by :slack
15
+ # deliver_by :custom, class: "MyDeliveryMethod"
16
+
17
+ # Add required params
18
+ #
19
+ param :message
20
+
21
+ # Define helper methods to make rendering easier.
22
+ #
23
+ # def message
24
+ # t(".message")
25
+ # end
26
+ #
27
+ # def url
28
+ # post_path(params[:post])
29
+ # end
30
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "csv"
4
+
5
+ # ExportCsvDocumentAccessLinksService
6
+ class ExportCsvDocumentAccessLinksService
7
+ def self.short_name
8
+ "Document Access Links"
9
+ end
10
+
11
+ def self.call(document_ids)
12
+ ActionCable.server.broadcast("export_channel", {progress: 0})
13
+
14
+ document_ids = document_ids.flatten
15
+ total = document_ids.size
16
+ count = 0
17
+ slice_count = 100
18
+ csv_file = []
19
+
20
+ Rails.logger.debug { "\n\nExportCsvDocumentAccessLinksService: #{document_ids.inspect}\n\n" }
21
+
22
+ CSV.generate(headers: true) do |_csv|
23
+ csv_file << DocumentAccess.column_names
24
+ document_ids.each_slice(slice_count) do |slice|
25
+ # Broadcast progress percentage
26
+ count += slice_count
27
+ progress = ((count.to_f / total) * 100).round
28
+ progress = 100 if progress > 100
29
+
30
+ ActionCable.server.broadcast("export_channel", {progress: progress})
31
+ slice.each do |doc_id|
32
+ doc = Document.find_by(friendlier_id: doc_id)
33
+
34
+ Rails.logger.debug { "\n\nDocAccessLinks: #{doc.document_accesses.size}\n\n" }
35
+
36
+ doc.document_accesses.each do |access|
37
+ csv_file << access.to_csv
38
+ end
39
+ rescue NoMethodError
40
+ Rails.logger.debug { "\n\nExport Failed: #{doc_id.inspect}\n\n" }
41
+ end
42
+ end
43
+ end
44
+
45
+ csv_file
46
+ end
47
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "csv"
4
+
5
+ # ExportCsvDocumentDownloadsService
6
+ class ExportCsvDocumentDownloadsService
7
+ def self.short_name
8
+ "Document Downloads"
9
+ end
10
+
11
+ def self.call(document_ids)
12
+ ActionCable.server.broadcast("export_channel", {progress: 0})
13
+
14
+ document_ids = document_ids.flatten
15
+ total = document_ids.size
16
+ count = 0
17
+ slice_count = 100
18
+ csv_file = []
19
+
20
+ Rails.logger.debug { "\n\nExportCsvDocumentDownloadsService: #{document_ids.inspect}\n\n" }
21
+
22
+ CSV.generate(headers: true) do |_csv|
23
+ csv_file << DocumentDownload.column_names
24
+ document_ids.each_slice(slice_count) do |slice|
25
+ # Broadcast progress percentage
26
+ count += slice_count
27
+ progress = ((count.to_f / total) * 100).round
28
+ progress = 100 if progress > 100
29
+
30
+ ActionCable.server.broadcast("export_channel", {progress: progress})
31
+ slice.each do |doc_id|
32
+ doc = Document.find_by(friendlier_id: doc_id)
33
+
34
+ Rails.logger.debug { "\n\nDocDownloads: #{doc.document_downloads.size}\n\n" }
35
+
36
+ doc.document_downloads.each do |download|
37
+ csv_file << download.to_csv
38
+ end
39
+ rescue NoMethodError
40
+ Rails.logger.debug { "\n\nExport Failed: #{doc_id.inspect}\n\n" }
41
+ end
42
+ end
43
+ end
44
+
45
+ csv_file
46
+ end
47
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "csv"
4
+
5
+ # ExportCsvService
6
+ class ExportCsvService
7
+ def self.short_name
8
+ "Documents"
9
+ end
10
+
11
+ def self.call(document_ids)
12
+ ActionCable.server.broadcast("export_channel", {progress: 0})
13
+
14
+ document_ids = document_ids.flatten
15
+ total = document_ids.size
16
+ count = 0
17
+ slice_count = 100
18
+ csv_file = []
19
+
20
+ Rails.logger.debug { "\n\nExportCsvService: #{document_ids.inspect}\n\n" }
21
+
22
+ CSV.generate(headers: true) do |_csv|
23
+ Rails.logger.debug { "\n\n CSV Fields: #{GeoblacklightAdmin::Schema.instance.exportable_fields.map { |k, _v| k.to_s }} \n\n" }
24
+
25
+ csv_file << GeoblacklightAdmin::Schema.instance.exportable_fields.map { |k, _v| k.to_s }
26
+ document_ids.each_slice(slice_count) do |slice|
27
+ # Broadcast progress percentage
28
+ count += slice_count
29
+ progress = ((count.to_f / total) * 100).round
30
+ progress = 100 if progress > 100
31
+
32
+ ActionCable.server.broadcast("export_channel", {progress: progress})
33
+ slice.each do |doc_id|
34
+ doc = Document.find_by(friendlier_id: doc_id)
35
+ csv_file << doc.to_csv
36
+ rescue NoMethodError
37
+ Rails.logger.debug { "\n\nExport Failed: #{doc_id.inspect}\n\n" }
38
+ end
39
+ end
40
+ end
41
+
42
+ csv_file
43
+ end
44
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ # ExportJsonService
6
+ class ExportJsonService
7
+ def self.call(document_ids)
8
+ ActionCable.server.broadcast("export_channel", {progress: 0})
9
+
10
+ document_ids = document_ids.flatten
11
+ total = document_ids.size
12
+ count = 0
13
+ slice_count = 100
14
+ documents = []
15
+
16
+ Rails.logger.debug { "\n\nExportJsonService: #{document_ids.inspect}\n\n" }
17
+
18
+ document_ids.each_slice(slice_count) do |slice|
19
+ # Broadcast progress percentage
20
+ count += slice_count
21
+ progress = ((count.to_f / total) * 100).round
22
+ progress = 100 if progress > 100
23
+
24
+ ActionCable.server.broadcast("export_channel", {progress: progress})
25
+ slice.each do |doc_id|
26
+ doc = Document.find_by(friendlier_id: doc_id)
27
+ documents << doc
28
+ rescue NoMethodError
29
+ Rails.logger.debug { "\n\nExport Failed: #{doc_id.inspect}\n\n" }
30
+ end
31
+ end
32
+
33
+ documents
34
+ end
35
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "zip"
4
+
5
+ # This is a simple example which uses rubyzip to
6
+ # recursively generate a zip file from the contents of
7
+ # a specified directory. The directory itself is not
8
+ # included in the archive, rather just its contents.
9
+ #
10
+ # Usage:
11
+ # directory_to_zip = "/tmp/input"
12
+ # output_file = "/tmp/out.zip"
13
+ # zf = ZipFileGenerator.new(directory_to_zip, output_file)
14
+ # zf.write()
15
+ class ZipFileGenerator
16
+ # Initialize with the directory to zip and the location of the output archive.
17
+ def initialize(input_dir, output_file)
18
+ @input_dir = input_dir
19
+ @output_file = output_file
20
+ end
21
+
22
+ # Zip the input directory.
23
+ def write
24
+ entries = Dir.entries(@input_dir) - %w[. ..]
25
+
26
+ ::Zip::File.open(@output_file, ::Zip::File::CREATE) do |zipfile|
27
+ write_entries entries, "", zipfile
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ # A helper method to make the recursion work.
34
+ def write_entries(entries, path, zipfile)
35
+ entries.each do |e|
36
+ zipfile_path = (path == "") ? e : File.join(path, e)
37
+ disk_file_path = File.join(@input_dir, zipfile_path)
38
+
39
+ if File.directory? disk_file_path
40
+ recursively_deflate_directory(disk_file_path, zipfile, zipfile_path)
41
+ else
42
+ put_into_archive(disk_file_path, zipfile, zipfile_path)
43
+ end
44
+ end
45
+ end
46
+
47
+ def recursively_deflate_directory(disk_file_path, zipfile, zipfile_path)
48
+ zipfile.mkdir zipfile_path
49
+ subdir = Dir.entries(disk_file_path) - %w[. ..]
50
+ write_entries subdir, zipfile_path, zipfile
51
+ end
52
+
53
+ def put_into_archive(disk_file_path, zipfile, zipfile_path)
54
+ zipfile.add(zipfile_path, disk_file_path)
55
+ end
56
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ json.data do
4
+ json.array! @presenter.documents do |document|
5
+ document_url = polymorphic_url(url_for_document(document))
6
+ json.id document.id
7
+ json.type document[blacklight_config.view_config(:index).display_type_field]
8
+ json.attributes do
9
+ doc_presenter = index_presenter(document)
10
+
11
+ doc_presenter.fields_to_render.each do |field_name, field|
12
+ json.partial! 'field', field: field,
13
+ field_name: field_name,
14
+ document_url: document_url,
15
+ doc_presenter: doc_presenter
16
+ end
17
+ end
18
+
19
+ json.links do
20
+ json.self document_url
21
+ end
22
+ end
23
+ end
24
+
25
+ json.included do
26
+ json.array! @presenter.search_facets do |facet|
27
+ json.type 'facet'
28
+ json.id facet.name
29
+ json.attributes do
30
+ facet_config = facet_configuration_for_field(facet.name)
31
+ json.label facet_field_label(facet_config.key)
32
+ json.items do
33
+ json.array! facet.items do |item|
34
+ json.id
35
+ json.attributes do
36
+ json.label item.label
37
+ json.value item.value
38
+ json.hits item.hits
39
+ end
40
+ json.links do
41
+ Deprecation.silence(Blacklight::FacetsHelperBehavior) do
42
+ if facet_in_params?(facet.name, item.value)
43
+ Deprecation.silence(Blacklight::SearchState) do
44
+ json.remove admin_advanced_search_action_path(search_state.remove_facet_params(facet.name, item.value))
45
+ end
46
+ else
47
+ json.self path_for_facet(facet.name, item.value, only_path: false)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ json.links do
55
+ json.self admin_advanced_search_facet_path(id: facet.name, only_path: false)
56
+ end
57
+ end
58
+
59
+ json.array! search_fields do |(label, key)|
60
+ json.type 'search_field'
61
+ json.id key
62
+ json.attributes do
63
+ json.label label
64
+ end
65
+ json.links do
66
+ json.self url_for(search_state.to_h.merge(search_field: key, only_path: false))
67
+ end
68
+ end
69
+
70
+ json.array! active_sort_fields do |key, field|
71
+ json.type 'sort'
72
+ json.id key
73
+ json.attributes do
74
+ json.label field.label
75
+ end
76
+ json.links do
77
+ json.self url_for(search_state.to_h.merge(sort: key, only_path: false))
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+ json.links do
3
+ json.self url_for(search_state.to_h.merge(only_path: false))
4
+ json.prev url_for(search_state.to_h.merge(only_path: false, page: @response.prev_page.to_s)) if @response.prev_page
5
+ json.next url_for(search_state.to_h.merge(only_path: false, page: @response.next_page.to_s)) if @response.next_page
6
+ json.last url_for(search_state.to_h.merge(only_path: false, page: @response.total_pages.to_s))
7
+ end
8
+
9
+ json.meta do
10
+ json.pages @presenter.pagination_info
11
+ end
12
+
13
+ json.data do
14
+ json.array! @presenter.documents do |document|
15
+ document_url = polymorphic_url(search_state.url_for_document(document))
16
+ json.id document.id
17
+ json.type document[blacklight_config.view_config(:index).display_type_field]
18
+ json.attributes do
19
+ doc_presenter = document_presenter(document)
20
+
21
+ doc_presenter.fields_to_render.each do |field_name, field|
22
+ json.partial! 'field', field: field,
23
+ field_name: field_name,
24
+ document_url: document_url,
25
+ doc_presenter: doc_presenter
26
+ end
27
+ end
28
+
29
+ json.links do
30
+ json.self document_url
31
+ end
32
+ end
33
+ end
34
+
35
+ json.included do
36
+ json.array! @presenter.search_facets do |facet|
37
+ json.type 'facet'
38
+ json.id facet.name
39
+ json.attributes do
40
+ facet_config = facet_configuration_for_field(facet.name)
41
+ json.label facet_field_label(facet_config.key)
42
+ json.items do
43
+ json.array! facet.items do |item|
44
+ json.id
45
+ json.attributes do
46
+ json.label item.label
47
+ json.value item.value
48
+ json.hits item.hits
49
+ end
50
+ json.links do
51
+ Deprecation.silence(Blacklight::FacetsHelperBehavior) do
52
+ if facet_in_params?(facet.name, item.value)
53
+ Deprecation.silence(Blacklight::SearchState) do
54
+ json.remove search_action_path(search_state.remove_facet_params(facet.name, item.value))
55
+ end
56
+ else
57
+ json.self path_for_facet(facet.name, item.value, only_path: false)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ json.links do
65
+ json.self search_facet_path(id: facet.name, only_path: false)
66
+ end
67
+ end
68
+
69
+ json.array! search_fields do |(label, key)|
70
+ json.type 'search_field'
71
+ json.id key
72
+ json.attributes do
73
+ json.label label
74
+ end
75
+ json.links do
76
+ json.self url_for(search_state.to_h.merge(search_field: key, only_path: false))
77
+ end
78
+ end
79
+
80
+ json.array! active_sort_fields do |key, field|
81
+ json.type 'sort'
82
+ json.id key
83
+ json.attributes do
84
+ json.label field.label
85
+ end
86
+ json.links do
87
+ json.self url_for(search_state.to_h.merge(sort: key, only_path: false))
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ json.set!(field_name) do
4
+ json.id "#{document_url}##{field_name}"
5
+ json.type 'document_value'
6
+ json.attributes do
7
+ json.value doc_presenter.field_value(field)
8
+ json.label field.label
9
+ end
10
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+ json.links do
3
+ json.self url_for(search_state.to_h.merge(only_path: false))
4
+ json.prev url_for(search_state.to_h.merge(only_path: false, page: @response.prev_page.to_s)) if @response.prev_page
5
+ json.next url_for(search_state.to_h.merge(only_path: false, page: @response.next_page.to_s)) if @response.next_page
6
+ json.last url_for(search_state.to_h.merge(only_path: false, page: @response.total_pages.to_s))
7
+ end
8
+
9
+ json.meta do
10
+ json.pages @presenter.pagination_info
11
+ end
12
+
13
+ json.data do
14
+ json.array! @presenter.documents do |document|
15
+ document_url = polymorphic_url(url_for_document(document))
16
+ json.id document.id
17
+ json.type document[blacklight_config.view_config(:index).display_type_field]
18
+ json.attributes do
19
+ doc_presenter = index_presenter(document)
20
+
21
+ doc_presenter.fields_to_render.each do |field_name, field|
22
+ json.partial! 'field', field: field,
23
+ field_name: field_name,
24
+ document_url: document_url,
25
+ doc_presenter: doc_presenter
26
+ end
27
+ end
28
+
29
+ json.links do
30
+ json.self document_url
31
+ end
32
+ end
33
+ end
34
+
35
+ json.included do
36
+ json.array! @presenter.search_facets do |facet|
37
+ json.type 'facet'
38
+ json.id facet.name
39
+ json.attributes do
40
+ facet_config = facet_configuration_for_field(facet.name)
41
+ json.label facet_field_label(facet_config.key)
42
+ json.items do
43
+ json.array! facet.items do |item|
44
+ json.id
45
+ json.attributes do
46
+ json.label item.label
47
+ json.value item.value
48
+ json.hits item.hits
49
+ end
50
+ json.links do
51
+ if facet_in_params?(facet.name, item.value)
52
+ json.remove search_action_path(search_state.remove_facet_params(facet.name, item.value))
53
+ else
54
+ json.self path_for_facet(facet.name, item.value, only_path: false)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ json.links do
61
+ json.self search_facet_path(id: facet.name, only_path: false)
62
+ end
63
+ end
64
+
65
+ json.array! search_fields do |(label, key)|
66
+ json.type 'search_field'
67
+ json.id key
68
+ json.attributes do
69
+ json.label label
70
+ end
71
+ json.links do
72
+ json.self url_for(search_state.to_h.merge(search_field: key, only_path: false))
73
+ end
74
+ end
75
+
76
+ json.array! active_sort_fields do |key, field|
77
+ json.type 'sort'
78
+ json.id key
79
+ json.attributes do
80
+ json.label field.label
81
+ end
82
+ json.links do
83
+ json.self url_for(search_state.to_h.merge(sort: key, only_path: false))
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+ json.links do
3
+ json.self url_for(search_state.to_h.merge(only_path: false))
4
+ json.prev url_for(search_state.to_h.merge(only_path: false, page: @response.prev_page.to_s)) if @response.prev_page
5
+ json.next url_for(search_state.to_h.merge(only_path: false, page: @response.next_page.to_s)) if @response.next_page
6
+ json.last url_for(search_state.to_h.merge(only_path: false, page: @response.total_pages.to_s))
7
+ end
8
+
9
+ json.meta do
10
+ json.pages @presenter.pagination_info
11
+ end
12
+
13
+ json.data do
14
+ json.array! @presenter.documents do |document|
15
+ document_url = polymorphic_url(search_state.url_for_document(document))
16
+ json.id document.id
17
+ json.type document[blacklight_config.view_config(:index).display_type_field]
18
+ json.attributes do
19
+ doc_presenter = document_presenter(document)
20
+
21
+ doc_presenter.fields_to_render.each do |field_name, field|
22
+ json.partial! 'field', field: field,
23
+ field_name: field_name,
24
+ document_url: document_url,
25
+ doc_presenter: doc_presenter
26
+ end
27
+ end
28
+
29
+ json.links do
30
+ json.self document_url
31
+ end
32
+ end
33
+ end
34
+
35
+ json.included do
36
+ json.array! @presenter.search_facets do |facet|
37
+ json.type 'facet'
38
+ json.id facet.name
39
+ json.attributes do
40
+ facet_config = facet_configuration_for_field(facet.name)
41
+ json.label facet_field_label(facet_config.key)
42
+ json.items do
43
+ json.array! facet.items do |item|
44
+ json.id
45
+ json.attributes do
46
+ json.label item.label
47
+ json.value item.value
48
+ json.hits item.hits
49
+ end
50
+ json.links do
51
+ Deprecation.silence(Blacklight::FacetsHelperBehavior) do
52
+ if facet_in_params?(facet.name, item.value)
53
+ Deprecation.silence(Blacklight::SearchState) do
54
+ json.remove search_action_path(search_state.remove_facet_params(facet.name, item.value))
55
+ end
56
+ else
57
+ json.self path_for_facet(facet.name, item.value, only_path: false)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ json.links do
65
+ json.self search_facet_path(id: facet.name, only_path: false)
66
+ end
67
+ end
68
+
69
+ json.array! search_fields do |(label, key)|
70
+ json.type 'search_field'
71
+ json.id key
72
+ json.attributes do
73
+ json.label label
74
+ end
75
+ json.links do
76
+ json.self url_for(search_state.to_h.merge(search_field: key, only_path: false))
77
+ end
78
+ end
79
+
80
+ json.array! active_sort_fields do |key, field|
81
+ json.type 'sort'
82
+ json.id key
83
+ json.attributes do
84
+ json.label field.label
85
+ end
86
+ json.links do
87
+ json.self url_for(search_state.to_h.merge(sort: key, only_path: false))
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ json.extract! bookmark, :id, :created_at, :updated_at
4
+ json.url bookmark_url(bookmark, format: :json)
@@ -0,0 +1,7 @@
1
+ <%# 1. Toggle bookmark icon %>
2
+ <%# 2. Swap link class %>
3
+
4
+ var result = $("#<%= @document.friendlier_id %>");
5
+ result.addClass('bookmarked');
6
+ result.find('span.create_bookmark').addClass('hidden');
7
+ result.find('span.destroy_bookmark').removeClass('hidden');
@@ -0,0 +1,7 @@
1
+ <%# 1. Toggle bookmark icon %>
2
+ <%# 2. Swap link class %>
3
+
4
+ var result = $("#<%= @document.friendlier_id %>");
5
+ result.removeClass('bookmarked');
6
+ result.find('span.create_bookmark').removeClass('hidden');
7
+ result.find('span.destroy_bookmark').addClass('hidden');
@@ -0,0 +1,21 @@
1
+ <p id="notice"><%= notice %></p>
2
+
3
+ <h1>Bookmarks (<%= current_user.bookmarks.size %>)</h1>
4
+
5
+ <p>
6
+ <%= render "admin/documents/result_toggle" %>
7
+ <%= render "admin/documents/result_selected_options" %>
8
+ <span class='float-right'>
9
+ <%== pagy_bootstrap_nav(@pagy) %>
10
+ </span>
11
+ </p>
12
+
13
+ <hr/>
14
+
15
+ <%= render "admin/documents/result_selection_options" %>
16
+
17
+ <ol id='results' class='list-unstyled' data-controller='results'>
18
+ <% @bookmarks.each_with_index do |bookmark, index| %>
19
+ <%= render 'admin/documents/document', document: bookmark.document, index: index %>
20
+ <% end %>
21
+ </ol>
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ json.array! @bookmarks, partial: "bookmarks/bookmark", as: :bookmark
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ json.extract! bulk_action, :id, :created_at, :updated_at
4
+ json.url admin_bulk_action_url(bulk_action, format: :json)