hyrax 5.2.0 → 5.3.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 (527) hide show
  1. checksums.yaml +4 -4
  2. data/.dassie/.env +5 -1
  3. data/.dassie/Gemfile +4 -2
  4. data/.dassie/app/assets/images/bulkrax/removed.png +0 -0
  5. data/.dassie/app/assets/javascripts/application.js +2 -0
  6. data/.dassie/app/assets/stylesheets/application.css +1 -0
  7. data/.dassie/app/controllers/catalog_controller.rb +1 -0
  8. data/.dassie/app/forms/admin_set_resource_form.rb +6 -0
  9. data/.dassie/app/forms/collection_resource_form.rb +5 -2
  10. data/.dassie/app/forms/generic_work_resource_form.rb +5 -2
  11. data/.dassie/app/forms/monograph_form.rb +5 -3
  12. data/.dassie/app/indexers/admin_set_resource_indexer.rb +5 -0
  13. data/.dassie/app/indexers/collection_resource_indexer.rb +3 -3
  14. data/.dassie/app/indexers/generic_work_resource_indexer.rb +6 -3
  15. data/.dassie/app/indexers/monograph_indexer.rb +6 -2
  16. data/.dassie/app/models/ability.rb +8 -0
  17. data/.dassie/app/models/collection_resource.rb +4 -2
  18. data/.dassie/app/models/concerns/bulkrax/has_local_processing.rb +8 -0
  19. data/.dassie/app/models/generic_work_resource.rb +5 -2
  20. data/.dassie/app/models/monograph.rb +5 -2
  21. data/.dassie/app/views/blacklight_dynamic_sitemap/sitemap/show.xml.builder +22 -0
  22. data/.dassie/bin/importer +142 -0
  23. data/.dassie/bin/web +4 -0
  24. data/.dassie/config/browse_everything_providers.yml +1 -1
  25. data/.dassie/config/bulkrax_api.yml +86 -0
  26. data/.dassie/config/initializers/bulkrax.rb +92 -0
  27. data/.dassie/config/initializers/clamav.rb +2 -0
  28. data/.dassie/config/initializers/hyrax.rb +7 -1
  29. data/.dassie/config/initializers/riiif.rb +4 -80
  30. data/.dassie/config/initializers/wings.rb +1 -1
  31. data/.dassie/config/metadata_profiles/m3_profile.yaml +929 -0
  32. data/.dassie/config/puma.rb +4 -2
  33. data/.dassie/config/routes.rb +7 -0
  34. data/.dassie/config/sidekiq.yml +17 -0
  35. data/.dassie/config/uv/uv.html +63 -81
  36. data/.dassie/db/migrate/20240606205215_create_hyrax_flexible_schemas.rb +9 -0
  37. data/.dassie/db/migrate/20240606205216_add_contexts_to_hyrax_flexible_schemas.rb +5 -0
  38. data/.dassie/db/migrate/20250826142438_create_bulkrax_importers.bulkrax.rb +19 -0
  39. data/.dassie/db/migrate/20250826142439_create_bulkrax_importer_runs.bulkrax.rb +17 -0
  40. data/.dassie/db/migrate/20250826142440_create_bulkrax_entries.bulkrax.rb +17 -0
  41. data/.dassie/db/migrate/20250826142441_add_status_to_entry.bulkrax.rb +10 -0
  42. data/.dassie/db/migrate/20250826142442_add_collections_to_importer_runs.bulkrax.rb +7 -0
  43. data/.dassie/db/migrate/20250826142443_change_collection_ids_on_entries.bulkrax.rb +6 -0
  44. data/.dassie/db/migrate/20250826142444_create_bulkrax_exporters.bulkrax.rb +20 -0
  45. data/.dassie/db/migrate/20250826142445_create_bulkrax_exporter_runs.bulkrax.rb +15 -0
  46. data/.dassie/db/migrate/20250826142446_change_importer_and_exporter_to_polymorphic.bulkrax.rb +19 -0
  47. data/.dassie/db/migrate/20250826142447_add_total_collection_records_to_importer_runs.bulkrax.rb +6 -0
  48. data/.dassie/db/migrate/20250826142448_add_children_to_importer_runs.bulkrax.rb +7 -0
  49. data/.dassie/db/migrate/20250826142449_change_total_records_to_total_work_entries.bulkrax.rb +7 -0
  50. data/.dassie/db/migrate/20250826142450_change_entry_last_error.bulkrax.rb +20 -0
  51. data/.dassie/db/migrate/20250826142451_add_validate_only_to_bulkrax_importers.bulkrax.rb +6 -0
  52. data/.dassie/db/migrate/20250826142452_add_status_to_importers.bulkrax.rb +10 -0
  53. data/.dassie/db/migrate/20250826142453_remove_foreign_key_from_bulkrax_entries.bulkrax.rb +6 -0
  54. data/.dassie/db/migrate/20250826142454_add_status_to_exporters.bulkrax.rb +8 -0
  55. data/.dassie/db/migrate/20250826142455_add_invalid_record_to_importer_run.bulkrax.rb +6 -0
  56. data/.dassie/db/migrate/20250826142456_create_bulkrax_statuses.bulkrax.rb +19 -0
  57. data/.dassie/db/migrate/20250826142457_move_to_statuses.bulkrax.rb +31 -0
  58. data/.dassie/db/migrate/20250826142458_add_date_filter_and_status_to_bulkrax_exporters.bulkrax.rb +8 -0
  59. data/.dassie/db/migrate/20250826142459_add_workflow_status_to_bulkrax_exporter.bulkrax.rb +6 -0
  60. data/.dassie/db/migrate/20250826142460_remove_unused_last_error.bulkrax.rb +8 -0
  61. data/.dassie/db/migrate/20250826142461_increase_text_sizes.bulkrax.rb +13 -0
  62. data/.dassie/db/migrate/20250826142462_change_bulkrax_statuses_error_message_column_type_to_text.bulkrax.rb +6 -0
  63. data/.dassie/db/migrate/20250826142463_rename_children_counters_to_relationships.bulkrax.rb +7 -0
  64. data/.dassie/db/migrate/20250826142464_add_file_set_counters_to_importer_runs.bulkrax.rb +8 -0
  65. data/.dassie/db/migrate/20250826142465_add_import_attempts_to_entries.bulkrax.rb +6 -0
  66. data/.dassie/db/migrate/20250826142466_add_work_counters_to_importer_runs.bulkrax.rb +7 -0
  67. data/.dassie/db/migrate/20250826142467_create_bulkrax_pending_relationships.bulkrax.rb +14 -0
  68. data/.dassie/db/migrate/20250826142468_add_order_to_bulkrax_pending_relationships.bulkrax.rb +6 -0
  69. data/.dassie/db/migrate/20250826142469_add_include_thumbnails_to_bulkrax_exporters.bulkrax.rb +6 -0
  70. data/.dassie/db/migrate/20250826142470_add_generated_metadata_to_bulkrax_exporters.bulkrax.rb +6 -0
  71. data/.dassie/db/migrate/20250826142471_rename_bulkrax_importer_run_to_importer_run.bulkrax.rb +18 -0
  72. data/.dassie/db/migrate/20250826142472_add_indices_to_bulkrax.bulkrax.rb +26 -0
  73. data/.dassie/db/migrate/20250826142473_denormalize_status_message.bulkrax.rb +8 -0
  74. data/.dassie/db/migrate/20250826142474_update_identifier_index.bulkrax.rb +7 -0
  75. data/.dassie/db/migrate/20250826142475_add_index_to_metadata_bulkrax_identifier.bulkrax.rb +19 -0
  76. data/.dassie/db/migrate/20250826142476_add_file_name_to_uploaded_files.bulkrax.rb +6 -0
  77. data/.dassie/db/migrate/20250826142477_add_error_tracking_to_pending_relationships.bulkrax.rb +6 -0
  78. data/.dassie/db/migrate/20250826142478_add_last_imported_at_to_bulkrax_importers.bulkrax.rb +6 -0
  79. data/.dassie/db/migrate/20250826142479_add_next_import_at_to_bulkrax_importers.bulkrax.rb +6 -0
  80. data/.dassie/db/migrate/20250826142480_entry_error_denormalization.bulkrax.rb +8 -0
  81. data/.dassie/db/migrate/20250826142481_faster_first_entry.bulkrax.rb +8 -0
  82. data/.dassie/db/migrate/20260430000001_create_hyrax_redirect_paths.hyrax.rb +13 -0
  83. data/.dassie/db/migrate/20260521003627_add_additional_redirect_info.hyrax.rb +32 -0
  84. data/.dassie/db/schema.rb +154 -1
  85. data/.dassie/package.json +1 -1
  86. data/.dassie/rspec_split_configuration.json +835 -0
  87. data/.dassie/solr/conf/solrconfig.xml +21 -5
  88. data/.github/{ISSUE_TEMPLATE.md → ISSUE_TEMPLATE/issue_template.md} +5 -0
  89. data/.github/workflows/lint-build-test.yml +5 -1
  90. data/.github/workflows/release-charts.yml +48 -0
  91. data/.gitignore +6 -0
  92. data/.koppie/.env +5 -1
  93. data/.koppie/Gemfile +3 -1
  94. data/.koppie/app/assets/images/bulkrax/removed.png +0 -0
  95. data/.koppie/app/assets/javascripts/application.js +2 -0
  96. data/.koppie/app/assets/stylesheets/application.css +1 -0
  97. data/.koppie/app/controllers/catalog_controller.rb +1 -1
  98. data/.koppie/app/forms/collection_resource_form.rb +5 -2
  99. data/.koppie/app/forms/file_set_form.rb +5 -0
  100. data/.koppie/app/forms/generic_work_form.rb +5 -3
  101. data/.koppie/app/forms/monograph_form.rb +5 -3
  102. data/.koppie/app/indexers/collection_resource_indexer.rb +5 -2
  103. data/.koppie/app/indexers/file_set_indexer.rb +7 -0
  104. data/.koppie/app/indexers/generic_work_indexer.rb +6 -3
  105. data/.koppie/app/indexers/monograph_indexer.rb +6 -2
  106. data/.koppie/app/models/ability.rb +8 -0
  107. data/.koppie/app/models/collection_resource.rb +4 -2
  108. data/.koppie/app/models/concerns/bulkrax/has_local_processing.rb +8 -0
  109. data/.koppie/app/models/generic_work.rb +5 -2
  110. data/.koppie/app/models/monograph.rb +5 -2
  111. data/.koppie/app/views/blacklight_dynamic_sitemap/sitemap/show.xml.builder +22 -0
  112. data/.koppie/bin/importer +142 -0
  113. data/.koppie/bin/web +4 -0
  114. data/.koppie/config/browse_everything_providers.yml +2 -0
  115. data/.koppie/config/bulkrax_api.yml +86 -0
  116. data/.koppie/config/initializers/bulkrax.rb +92 -0
  117. data/.koppie/config/initializers/clamav.rb +2 -0
  118. data/.koppie/config/initializers/hyrax.rb +11 -3
  119. data/.koppie/config/initializers/riiif.rb +4 -82
  120. data/.koppie/config/metadata_profiles/m3_profile.yaml +930 -0
  121. data/.koppie/config/routes.rb +7 -0
  122. data/.koppie/config/sidekiq.yml +2 -0
  123. data/.koppie/config/uv/uv.html +63 -81
  124. data/.koppie/db/migrate/20240606205215_create_hyrax_flexible_schemas.rb +9 -0
  125. data/.koppie/db/migrate/20240606205216_add_contexts_to_hyrax_flexible_schemas.rb +5 -0
  126. data/.koppie/db/migrate/20250826142438_create_bulkrax_importers.bulkrax.rb +19 -0
  127. data/.koppie/db/migrate/20250826142439_create_bulkrax_importer_runs.bulkrax.rb +17 -0
  128. data/.koppie/db/migrate/20250826142440_create_bulkrax_entries.bulkrax.rb +17 -0
  129. data/.koppie/db/migrate/20250826142441_add_status_to_entry.bulkrax.rb +10 -0
  130. data/.koppie/db/migrate/20250826142442_add_collections_to_importer_runs.bulkrax.rb +7 -0
  131. data/.koppie/db/migrate/20250826142443_change_collection_ids_on_entries.bulkrax.rb +6 -0
  132. data/.koppie/db/migrate/20250826142444_create_bulkrax_exporters.bulkrax.rb +20 -0
  133. data/.koppie/db/migrate/20250826142445_create_bulkrax_exporter_runs.bulkrax.rb +15 -0
  134. data/.koppie/db/migrate/20250826142446_change_importer_and_exporter_to_polymorphic.bulkrax.rb +19 -0
  135. data/.koppie/db/migrate/20250826142447_add_total_collection_records_to_importer_runs.bulkrax.rb +6 -0
  136. data/.koppie/db/migrate/20250826142448_add_children_to_importer_runs.bulkrax.rb +7 -0
  137. data/.koppie/db/migrate/20250826142449_change_total_records_to_total_work_entries.bulkrax.rb +7 -0
  138. data/.koppie/db/migrate/20250826142450_change_entry_last_error.bulkrax.rb +20 -0
  139. data/.koppie/db/migrate/20250826142451_add_validate_only_to_bulkrax_importers.bulkrax.rb +6 -0
  140. data/.koppie/db/migrate/20250826142452_add_status_to_importers.bulkrax.rb +10 -0
  141. data/.koppie/db/migrate/20250826142453_remove_foreign_key_from_bulkrax_entries.bulkrax.rb +6 -0
  142. data/.koppie/db/migrate/20250826142454_add_status_to_exporters.bulkrax.rb +8 -0
  143. data/.koppie/db/migrate/20250826142455_add_invalid_record_to_importer_run.bulkrax.rb +6 -0
  144. data/.koppie/db/migrate/20250826142456_create_bulkrax_statuses.bulkrax.rb +19 -0
  145. data/.koppie/db/migrate/20250826142457_move_to_statuses.bulkrax.rb +31 -0
  146. data/.koppie/db/migrate/20250826142458_add_date_filter_and_status_to_bulkrax_exporters.bulkrax.rb +8 -0
  147. data/.koppie/db/migrate/20250826142459_add_workflow_status_to_bulkrax_exporter.bulkrax.rb +6 -0
  148. data/.koppie/db/migrate/20250826142460_remove_unused_last_error.bulkrax.rb +8 -0
  149. data/.koppie/db/migrate/20250826142461_increase_text_sizes.bulkrax.rb +13 -0
  150. data/.koppie/db/migrate/20250826142462_change_bulkrax_statuses_error_message_column_type_to_text.bulkrax.rb +6 -0
  151. data/.koppie/db/migrate/20250826142463_rename_children_counters_to_relationships.bulkrax.rb +7 -0
  152. data/.koppie/db/migrate/20250826142464_add_file_set_counters_to_importer_runs.bulkrax.rb +8 -0
  153. data/.koppie/db/migrate/20250826142465_add_import_attempts_to_entries.bulkrax.rb +6 -0
  154. data/.koppie/db/migrate/20250826142466_add_work_counters_to_importer_runs.bulkrax.rb +7 -0
  155. data/.koppie/db/migrate/20250826142467_create_bulkrax_pending_relationships.bulkrax.rb +14 -0
  156. data/.koppie/db/migrate/20250826142468_add_order_to_bulkrax_pending_relationships.bulkrax.rb +6 -0
  157. data/.koppie/db/migrate/20250826142469_add_include_thumbnails_to_bulkrax_exporters.bulkrax.rb +6 -0
  158. data/.koppie/db/migrate/20250826142470_add_generated_metadata_to_bulkrax_exporters.bulkrax.rb +6 -0
  159. data/.koppie/db/migrate/20250826142471_rename_bulkrax_importer_run_to_importer_run.bulkrax.rb +18 -0
  160. data/.koppie/db/migrate/20250826142472_add_indices_to_bulkrax.bulkrax.rb +26 -0
  161. data/.koppie/db/migrate/20250826142473_denormalize_status_message.bulkrax.rb +8 -0
  162. data/.koppie/db/migrate/20250826142474_update_identifier_index.bulkrax.rb +7 -0
  163. data/.koppie/db/migrate/20250826142475_add_index_to_metadata_bulkrax_identifier.bulkrax.rb +19 -0
  164. data/.koppie/db/migrate/20250826142476_add_file_name_to_uploaded_files.bulkrax.rb +6 -0
  165. data/.koppie/db/migrate/20250826142477_add_error_tracking_to_pending_relationships.bulkrax.rb +6 -0
  166. data/.koppie/db/migrate/20250826142478_add_last_imported_at_to_bulkrax_importers.bulkrax.rb +6 -0
  167. data/.koppie/db/migrate/20250826142479_add_next_import_at_to_bulkrax_importers.bulkrax.rb +6 -0
  168. data/.koppie/db/migrate/20250826142480_entry_error_denormalization.bulkrax.rb +8 -0
  169. data/.koppie/db/migrate/20250826142481_faster_first_entry.bulkrax.rb +8 -0
  170. data/.koppie/db/migrate/20260430000001_create_hyrax_redirect_paths.hyrax.rb +13 -0
  171. data/.koppie/db/migrate/20260521003627_add_additional_redirect_info.hyrax.rb +32 -0
  172. data/.koppie/db/schema.rb +154 -1
  173. data/.koppie/package.json +1 -1
  174. data/.koppie/rspec_split_configuration.json +835 -0
  175. data/.koppie/solr/conf/solrconfig.xml +0 -5
  176. data/.koppie/yarn.lock +5587 -752
  177. data/.rubocop.yml +1 -0
  178. data/CONTAINERS.md +2 -0
  179. data/Dockerfile +9 -22
  180. data/Gemfile +0 -1
  181. data/Gemfile.allinson +2 -0
  182. data/README.md +1 -2
  183. data/app/actors/hyrax/actors/file_actor.rb +2 -0
  184. data/app/actors/hyrax/actors/file_set_actor.rb +1 -1
  185. data/app/assets/javascripts/hyrax/app.js.erb +143 -10
  186. data/app/assets/javascripts/hyrax/collection_select.js +68 -0
  187. data/app/assets/javascripts/hyrax/copy_permalink_button.js +28 -0
  188. data/app/assets/javascripts/hyrax/redirects.js +45 -0
  189. data/app/assets/javascripts/hyrax/relationships/control.es6 +21 -1
  190. data/app/assets/javascripts/hyrax/select_work_type.es6 +7 -2
  191. data/app/assets/javascripts/hyrax.js +3 -1
  192. data/app/assets/stylesheets/hyrax/_file-show.scss +1 -0
  193. data/app/assets/stylesheets/hyrax/_viewer.scss +8 -0
  194. data/app/assets/stylesheets/hyrax/dashboard.scss +22 -1
  195. data/app/assets/stylesheets/hyrax/sidebar.scss +98 -3
  196. data/app/authorities/qa/authorities/collections.rb +9 -9
  197. data/app/controllers/concerns/hyrax/analytics_error_handling.rb +97 -0
  198. data/app/controllers/concerns/hyrax/collections_controller_behavior.rb +3 -1
  199. data/app/controllers/concerns/hyrax/ensure_migrated_behavior.rb +50 -0
  200. data/app/controllers/concerns/hyrax/flexible_catalog_behavior.rb +206 -0
  201. data/app/controllers/concerns/hyrax/flexible_schema_behavior.rb +17 -0
  202. data/app/controllers/concerns/hyrax/redirect_to_display_url.rb +54 -0
  203. data/app/controllers/concerns/hyrax/works_controller_behavior.rb +52 -10
  204. data/app/controllers/hyrax/admin/admin_sets_controller.rb +21 -13
  205. data/app/controllers/hyrax/admin/analytics/collection_reports_controller.rb +2 -0
  206. data/app/controllers/hyrax/admin/analytics/work_reports_controller.rb +1 -0
  207. data/app/controllers/hyrax/admin/metadata_profiles_controller.rb +66 -0
  208. data/app/controllers/hyrax/batch_uploads_controller.rb +2 -0
  209. data/app/controllers/hyrax/dashboard/collections_controller.rb +27 -6
  210. data/app/controllers/hyrax/dashboard/nest_collections_controller.rb +2 -1
  211. data/app/controllers/hyrax/dashboard_controller.rb +2 -1
  212. data/app/controllers/hyrax/file_sets_controller.rb +19 -1
  213. data/app/controllers/hyrax/homepage_controller.rb +7 -0
  214. data/app/controllers/hyrax/my/works_controller.rb +2 -21
  215. data/app/controllers/hyrax/permissions_controller.rb +4 -2
  216. data/app/controllers/hyrax/redirects_controller.rb +56 -0
  217. data/app/controllers/hyrax/single_use_links_viewer_controller.rb +2 -1
  218. data/app/controllers/hyrax/transcripts_controller.rb +31 -0
  219. data/app/controllers/hyrax/uploads_controller.rb +18 -9
  220. data/app/forms/concerns/hyrax/based_near_field_behavior.rb +77 -0
  221. data/app/forms/concerns/hyrax/flexible_form_behavior.rb +37 -0
  222. data/app/forms/concerns/hyrax/redirects_field_behavior.rb +95 -0
  223. data/app/forms/concerns/hyrax/transcripts_behavior.rb +40 -0
  224. data/app/forms/hyrax/forms/admin_set_form.rb +1 -1
  225. data/app/forms/hyrax/forms/administrative_set_form.rb +3 -0
  226. data/app/forms/hyrax/forms/batch_edit_form.rb +1 -3
  227. data/app/forms/hyrax/forms/batch_upload_form.rb +14 -0
  228. data/app/forms/hyrax/forms/file_set_edit_form.rb +1 -1
  229. data/app/forms/hyrax/forms/file_set_form.rb +6 -7
  230. data/app/forms/hyrax/forms/pcdm_collection_form.rb +17 -5
  231. data/app/forms/hyrax/forms/pcdm_object_form.rb +11 -3
  232. data/app/forms/hyrax/forms/resource_batch_edit_form.rb +8 -22
  233. data/app/forms/hyrax/forms/resource_form.rb +110 -10
  234. data/app/forms/hyrax/forms.rb +1 -0
  235. data/app/helpers/hyrax/attributes_helper.rb +109 -0
  236. data/app/helpers/hyrax/blacklight_override.rb +26 -0
  237. data/app/helpers/hyrax/collections_helper.rb +2 -0
  238. data/app/helpers/hyrax/file_set_form_helper.rb +24 -0
  239. data/app/helpers/hyrax/hyrax_helper_behavior.rb +51 -2
  240. data/app/helpers/hyrax/iiif_helper.rb +11 -1
  241. data/app/helpers/hyrax/permalink_helper.rb +37 -0
  242. data/app/helpers/hyrax/redirects_tab_helper.rb +29 -0
  243. data/app/helpers/hyrax/work_form_helper.rb +9 -5
  244. data/app/helpers/hyrax/works_helper.rb +14 -0
  245. data/app/indexers/concerns/hyrax/workflow_indexer.rb +30 -0
  246. data/app/indexers/hyrax/file_set_indexer.rb +1 -0
  247. data/app/indexers/hyrax/indexers/administrative_set_indexer.rb +2 -1
  248. data/app/indexers/hyrax/indexers/file_set_indexer.rb +6 -2
  249. data/app/indexers/hyrax/indexers/pcdm_collection_indexer.rb +11 -1
  250. data/app/indexers/hyrax/indexers/pcdm_object_indexer.rb +25 -4
  251. data/app/indexers/hyrax/indexers/redirects_indexer.rb +29 -0
  252. data/app/indexers/hyrax/indexers/resource_indexer.rb +4 -0
  253. data/app/indexers/hyrax/indexers.rb +2 -0
  254. data/app/inputs/controlled_vocabulary_input.rb +7 -1
  255. data/app/jobs/content_deposit_error_event_job.rb +14 -0
  256. data/app/jobs/create_work_job.rb +2 -0
  257. data/app/jobs/migrate_files_to_valkyrie_job.rb +7 -1
  258. data/app/models/batch_upload_item.rb +4 -0
  259. data/app/models/concerns/hyrax/ability/flexible_metadata_ability.rb +10 -0
  260. data/app/models/concerns/hyrax/ability.rb +3 -1
  261. data/app/models/concerns/hyrax/collection_behavior.rb +4 -0
  262. data/app/models/concerns/hyrax/file_set/transcripts.rb +16 -0
  263. data/app/models/concerns/hyrax/file_set_behavior.rb +9 -0
  264. data/app/models/concerns/hyrax/flexibility.rb +107 -0
  265. data/app/models/concerns/hyrax/redirects_normalization.rb +38 -0
  266. data/app/models/concerns/hyrax/solr_document/characterization.rb +1 -1
  267. data/app/models/concerns/hyrax/solr_document/metadata.rb +9 -0
  268. data/app/models/concerns/hyrax/solr_document/ordered_members.rb +4 -0
  269. data/app/models/concerns/hyrax/solr_document_behavior.rb +28 -6
  270. data/app/models/concerns/hyrax/suppressible.rb +1 -1
  271. data/app/models/concerns/hyrax/valkyrie_lazy_migration.rb +1 -1
  272. data/app/models/concerns/hyrax/with_embargoes_and_leases.rb +30 -0
  273. data/app/models/concerns/hyrax/work_behavior.rb +8 -0
  274. data/app/models/hyrax/administrative_set.rb +1 -1
  275. data/app/models/hyrax/change_set.rb +3 -1
  276. data/app/models/hyrax/embargo.rb +3 -1
  277. data/app/models/hyrax/file_set.rb +4 -2
  278. data/app/models/hyrax/flexible_schema.rb +219 -0
  279. data/app/models/hyrax/lease.rb +3 -1
  280. data/app/models/hyrax/pcdm_collection.rb +4 -1
  281. data/app/models/hyrax/redirect.rb +64 -0
  282. data/app/models/hyrax/redirect_path.rb +14 -0
  283. data/app/models/hyrax/resource.rb +22 -25
  284. data/app/models/hyrax/riiif/file.rb +43 -0
  285. data/app/models/hyrax/riiif/file_resolver.rb +65 -0
  286. data/app/models/hyrax/uploaded_file.rb +9 -0
  287. data/app/models/hyrax/virus_scanner.rb +16 -3
  288. data/app/models/hyrax/work.rb +4 -1
  289. data/app/models/job_io_wrapper.rb +12 -3
  290. data/app/models/user_mailbox.rb +3 -1
  291. data/app/presenters/hyrax/admin_set_presenter.rb +11 -0
  292. data/app/presenters/hyrax/annotates_content.rb +35 -0
  293. data/app/presenters/hyrax/collection_presenter.rb +5 -1
  294. data/app/presenters/hyrax/displays_content.rb +133 -0
  295. data/app/presenters/hyrax/displays_image.rb +11 -4
  296. data/app/presenters/hyrax/displays_transcripts.rb +59 -0
  297. data/app/presenters/hyrax/file_set_presenter.rb +8 -18
  298. data/app/presenters/hyrax/google_scholar_presenter.rb +39 -0
  299. data/app/presenters/hyrax/iiif_manifest_presenter.rb +22 -4
  300. data/app/presenters/hyrax/missing_method_behavior.rb +15 -0
  301. data/app/presenters/hyrax/pcdm_member_presenter_factory.rb +2 -4
  302. data/app/presenters/hyrax/work_show_presenter.rb +56 -14
  303. data/app/renderers/hyrax/renderers/attribute_renderer.rb +6 -2
  304. data/app/renderers/hyrax/renderers/license_attribute_renderer.rb +10 -10
  305. data/app/renderers/hyrax/renderers/redirects_label_attribute_renderer.rb +25 -0
  306. data/app/renderers/hyrax/renderers/rights_statement_attribute_renderer.rb +10 -11
  307. data/app/search_builders/hyrax/dashboard/nested_collections_search_builder.rb +1 -5
  308. data/app/search_builders/hyrax/filter_by_type.rb +1 -1
  309. data/app/services/hyrax/action/create_valkyrie_work.rb +3 -2
  310. data/app/services/hyrax/authority_rendering_helper.rb +28 -0
  311. data/app/services/hyrax/authority_service.rb +107 -0
  312. data/app/services/hyrax/callbacks.rb +2 -2
  313. data/app/services/hyrax/collections/nested_collection_query_service.rb +9 -3
  314. data/app/services/hyrax/collections_service.rb +17 -0
  315. data/app/services/hyrax/custom_queries/find_by_property_value.rb +89 -0
  316. data/app/services/hyrax/edit_permissions_service.rb +4 -4
  317. data/app/services/hyrax/file_set_type_service.rb +12 -4
  318. data/app/services/hyrax/flexible_schema_validator_service.rb +153 -0
  319. data/app/services/hyrax/flexible_schema_validators/class_validator.rb +123 -0
  320. data/app/services/hyrax/flexible_schema_validators/core_metadata_validator.rb +211 -0
  321. data/app/services/hyrax/flexible_schema_validators/existing_records_validator.rb +83 -0
  322. data/app/services/hyrax/flexible_schema_validators/redirects_validator.rb +116 -0
  323. data/app/services/hyrax/flexible_schema_validators/schema_validator.rb +34 -0
  324. data/app/services/hyrax/flexible_schema_validators/sort_properties_validator.rb +54 -0
  325. data/app/services/hyrax/license_service.rb +1 -1
  326. data/app/services/hyrax/listeners/metadata_index_listener.rb +11 -0
  327. data/app/services/hyrax/m3_profile_editor.rb +32 -0
  328. data/app/services/hyrax/m3_schema_loader.rb +119 -0
  329. data/app/services/hyrax/manifest_builder_service.rb +18 -24
  330. data/app/services/hyrax/permalink_path.rb +25 -0
  331. data/app/services/hyrax/qa_select_service.rb +9 -5
  332. data/app/services/hyrax/redirect_path_normalizer.rb +58 -0
  333. data/app/services/hyrax/redirects_lookup.rb +59 -0
  334. data/app/services/hyrax/resource_permissions_visibility_propagator.rb +54 -0
  335. data/app/services/hyrax/resource_types_service.rb +3 -20
  336. data/app/services/hyrax/rights_statement_service.rb +1 -1
  337. data/app/services/hyrax/schema_loader.rb +205 -0
  338. data/app/services/hyrax/search_service.rb +1 -1
  339. data/app/services/hyrax/simple_schema_loader.rb +28 -127
  340. data/app/services/hyrax/solr_service.rb +39 -2
  341. data/app/services/hyrax/tolerant_select_service.rb +5 -3
  342. data/app/services/hyrax/valkyrie_upload.rb +2 -2
  343. data/app/services/hyrax/visibility_propagator.rb +4 -1
  344. data/app/services/hyrax/work_uploads_handler.rb +17 -9
  345. data/app/services/hyrax/workflow/workflow_factory.rb +5 -4
  346. data/app/services/migrate_resource_service.rb +7 -1
  347. data/app/uploaders/hyrax/uploaded_file_uploader.rb +2 -2
  348. data/app/utils/hyrax/data_destroyers/collection_branding_destroyer.rb +1 -1
  349. data/app/utils/hyrax/required_data_seeder.rb +1 -0
  350. data/app/utils/hyrax/required_data_seeders/collection_type_seeder.rb +1 -1
  351. data/app/utils/hyrax/required_data_seeders/flexible_profile_seeder.rb +28 -0
  352. data/app/validators/hyrax/controlled_vocabulary_validator.rb +64 -0
  353. data/app/validators/hyrax/redirect_validator.rb +128 -0
  354. data/app/views/catalog/_thumbnail_list_default.html.erb +2 -2
  355. data/app/views/collections/edit_fields/_schema_version.html.erb +1 -0
  356. data/app/views/hyrax/admin/admin_sets/_form_metadata.html.erb +24 -2
  357. data/app/views/hyrax/admin/admin_sets/_show_document_list_row.html.erb +1 -1
  358. data/app/views/hyrax/admin/admin_sets/show.html.erb +1 -1
  359. data/app/views/hyrax/admin/analytics/_analytics_error.html.erb +42 -0
  360. data/app/views/hyrax/admin/analytics/collection_reports/index.html.erb +11 -9
  361. data/app/views/hyrax/admin/analytics/work_reports/index.html.erb +60 -57
  362. data/app/views/hyrax/admin/features/index.html.erb +1 -1
  363. data/app/views/hyrax/admin/metadata_profiles/_import_modal.html.erb +20 -0
  364. data/app/views/hyrax/admin/metadata_profiles/index.html.erb +54 -0
  365. data/app/views/hyrax/base/_attribute_rows.html.erb +4 -21
  366. data/app/views/hyrax/base/_citations.html.erb +1 -0
  367. data/app/views/hyrax/base/_currently_shared.html.erb +2 -1
  368. data/app/views/hyrax/base/_file_manager_thumbnail.html.erb +1 -1
  369. data/app/views/hyrax/base/_form_member_of_collections.html.erb +6 -6
  370. data/app/views/hyrax/base/_form_redirects.html.erb +125 -0
  371. data/app/views/hyrax/base/_form_share.html.erb +7 -2
  372. data/app/views/hyrax/base/_member.html.erb +1 -1
  373. data/app/views/hyrax/base/_social_media.html.erb +1 -1
  374. data/app/views/hyrax/base/iiif_viewers/_universal_viewer.html.erb +1 -1
  375. data/app/views/hyrax/base/show.html.erb +3 -0
  376. data/app/views/hyrax/collections/_default_group.html.erb +3 -0
  377. data/app/views/hyrax/collections/_list_collections.html.erb +3 -0
  378. data/app/views/hyrax/collections/_list_works.html.erb +1 -1
  379. data/app/views/hyrax/collections/_show_document_list_row.html.erb +1 -1
  380. data/app/views/hyrax/collections/show.html.erb +4 -0
  381. data/app/views/hyrax/dashboard/_sidebar.html.erb +4 -2
  382. data/app/views/hyrax/dashboard/collections/_button_for_update_collection.html.erb +2 -1
  383. data/app/views/hyrax/dashboard/collections/_default_group.html.erb +3 -0
  384. data/app/views/hyrax/dashboard/collections/_form.html.erb +17 -0
  385. data/app/views/hyrax/dashboard/collections/_form_for_select_collection.html.erb +7 -10
  386. data/app/views/hyrax/dashboard/collections/_list_collections.html.erb +3 -0
  387. data/app/views/hyrax/dashboard/collections/_list_works.html.erb +1 -1
  388. data/app/views/hyrax/dashboard/collections/_show_document_list_row.html.erb +1 -1
  389. data/app/views/hyrax/dashboard/profiles/_edit_primary.html.erb +1 -8
  390. data/app/views/hyrax/dashboard/profiles/_trophy_edit.html.erb +1 -1
  391. data/app/views/hyrax/dashboard/profiles/show.html.erb +5 -5
  392. data/app/views/hyrax/dashboard/sidebar/_metadata.html.erb +11 -0
  393. data/app/views/hyrax/dashboard/sidebar/_repository_content.html.erb +1 -0
  394. data/app/views/hyrax/dashboard/works/_default_group.html.erb +3 -0
  395. data/app/views/hyrax/dashboard/works/_list_works.html.erb +4 -2
  396. data/app/views/hyrax/file_sets/_form.html.erb +16 -3
  397. data/app/views/hyrax/file_sets/_metadata.html.erb +35 -0
  398. data/app/views/hyrax/file_sets/_valkyrie_form.html.erb +37 -0
  399. data/app/views/hyrax/file_sets/edit.html.erb +14 -8
  400. data/app/views/hyrax/file_sets/media_display/_audio.html.erb +4 -0
  401. data/app/views/hyrax/file_sets/media_display/_image.html.erb +2 -2
  402. data/app/views/hyrax/file_sets/media_display/_video.html.erb +4 -0
  403. data/app/views/hyrax/homepage/_explore_collections.html.erb +1 -1
  404. data/app/views/hyrax/homepage/_featured_fields.html.erb +1 -1
  405. data/app/views/hyrax/homepage/_recent_document.html.erb +1 -1
  406. data/app/views/hyrax/homepage/robots.text.erb +17 -0
  407. data/app/views/hyrax/my/collections/_default_group.html.erb +3 -0
  408. data/app/views/hyrax/my/collections/_list_collections.html.erb +3 -0
  409. data/app/views/hyrax/my/collections/_modal_add_subcollection.html.erb +2 -2
  410. data/app/views/hyrax/my/collections/_modal_add_to_collection.html.erb +2 -2
  411. data/app/views/hyrax/my/works/_default_group.html.erb +3 -0
  412. data/app/views/hyrax/my/works/_list_works.html.erb +5 -2
  413. data/app/views/hyrax/shared/_copy_permalink.html.erb +10 -0
  414. data/app/views/hyrax/users/_user_info.html.erb +1 -6
  415. data/app/views/layouts/_head_tag_content.html.erb +2 -0
  416. data/app/views/layouts/hyrax/dashboard.html.erb +2 -1
  417. data/app/views/records/edit_fields/_contexts.html.erb +1 -0
  418. data/app/views/records/edit_fields/_license.html.erb +17 -5
  419. data/app/views/records/edit_fields/_resource_type.html.erb +16 -2
  420. data/app/views/records/edit_fields/_rights_statement.html.erb +17 -5
  421. data/app/views/records/edit_fields/_schema_version.html.erb +1 -0
  422. data/app/views/records/edit_fields/_transcript_ids.html.erb +18 -0
  423. data/app/views/records/show_fields/_rights.html.erb +1 -1
  424. data/app/views/shared/_citations.html.erb +46 -31
  425. data/app/views/shared/_schema_version.html.erb +38 -0
  426. data/bin/dev-entrypoint.sh +14 -4
  427. data/chart/hyrax/Chart.yaml +4 -4
  428. data/chart/hyrax/templates/ingress.yaml +3 -0
  429. data/chart/hyrax/values.yaml +10 -8
  430. data/config/features.rb +27 -0
  431. data/config/initializers/blacklight_dynamic_sitemap.rb +43 -0
  432. data/config/initializers/deprecation_patch.rb +27 -0
  433. data/config/initializers/hydra_works.rb +3 -0
  434. data/config/initializers/i18n_extensions.rb +197 -0
  435. data/config/initializers/storage_adapter_initializer.rb +15 -9
  436. data/config/locales/hyrax.de.yml +172 -54
  437. data/config/locales/hyrax.en.yml +183 -66
  438. data/config/locales/hyrax.es.yml +174 -49
  439. data/config/locales/hyrax.fr.yml +169 -45
  440. data/config/locales/hyrax.it.yml +172 -48
  441. data/config/locales/hyrax.pt-BR.yml +172 -54
  442. data/config/locales/hyrax.zh.yml +145 -21
  443. data/config/metadata/basic_metadata.yaml +66 -0
  444. data/config/metadata/batch_edit_metadata.yaml +119 -0
  445. data/config/metadata/file_set_metadata.yaml +19 -0
  446. data/config/metadata/redirects.yaml +15 -0
  447. data/config/metadata_profiles/m3_json_schema.json +487 -0
  448. data/config/metadata_profiles/m3_profile.yaml +954 -0
  449. data/config/routes.rb +9 -0
  450. data/docker-compose-allinson.yml +176 -0
  451. data/docker-compose-dassie.yml +14 -6
  452. data/docker-compose-koppie.yml +18 -10
  453. data/docker-compose-sirenia.yml +20 -10
  454. data/documentation/copy_permalink.md +29 -0
  455. data/documentation/developing-your-hyrax-based-app.md +2 -2
  456. data/documentation/file-ingest-characterization.md +763 -0
  457. data/documentation/flexible_metadata.md +113 -0
  458. data/documentation/forms/field_behaviors.md +297 -0
  459. data/documentation/redirects.md +428 -0
  460. data/hyrax.gemspec +7 -2
  461. data/lib/freyja/metadata_adapter.rb +1 -1
  462. data/lib/freyja/persister.rb +25 -1
  463. data/lib/generators/hyrax/collection_resource/collection_resource_generator.rb +2 -2
  464. data/lib/generators/hyrax/collection_resource/templates/collection.rb.erb +5 -1
  465. data/lib/generators/hyrax/collection_resource/templates/collection_form.rb.erb +5 -1
  466. data/lib/generators/hyrax/collection_resource/templates/collection_indexer.rb.erb +6 -1
  467. data/lib/generators/hyrax/iiif_viewer/USAGE +22 -0
  468. data/lib/generators/hyrax/iiif_viewer/iiif_viewer_generator.rb +49 -0
  469. data/lib/generators/hyrax/iiif_viewer/templates/_clover.html.erb +7 -0
  470. data/lib/generators/hyrax/iiif_viewer/templates/clover/clover.css +3328 -0
  471. data/lib/generators/hyrax/iiif_viewer/templates/clover/clover.html +16 -0
  472. data/lib/generators/hyrax/iiif_viewer/templates/clover/clover.js +237 -0
  473. data/lib/generators/hyrax/install_generator.rb +25 -1
  474. data/lib/generators/hyrax/riiif_generator.rb +1 -1
  475. data/lib/generators/hyrax/templates/app/views/blacklight_dynamic_sitemap/sitemap/show.xml.builder +22 -0
  476. data/lib/generators/hyrax/templates/config/clamav.rb +2 -0
  477. data/lib/generators/hyrax/templates/config/initializers/riiif.rb +4 -80
  478. data/lib/generators/hyrax/templates/db/migrate/20240606205215_create_hyrax_flexible_schemas.rb.erb +9 -0
  479. data/lib/generators/hyrax/templates/db/migrate/20240606205216_add_contexts_to_hyrax_flexible_schemas.rb.erb +5 -0
  480. data/lib/generators/hyrax/templates/db/migrate/20260430000001_create_hyrax_redirect_paths.rb.erb +22 -0
  481. data/lib/generators/hyrax/templates/db/migrate/20260521003627_add_additional_redirect_info.rb.erb +39 -0
  482. data/lib/generators/hyrax/templates/package.json +1 -1
  483. data/lib/generators/hyrax/templates/uv.html +60 -82
  484. data/lib/generators/hyrax/work/templates/indexer.rb.erb +1 -1
  485. data/lib/generators/hyrax/work/templates/model.rb.erb +5 -1
  486. data/lib/generators/hyrax/work_resource/templates/form.rb.erb +5 -2
  487. data/lib/generators/hyrax/work_resource/templates/indexer.rb.erb +6 -2
  488. data/lib/generators/hyrax/work_resource/templates/work.rb.erb +5 -2
  489. data/lib/generators/hyrax/work_resource/work_resource_generator.rb +1 -0
  490. data/lib/hyrax/active_fedora_dummy_model.rb +6 -0
  491. data/lib/hyrax/configuration.rb +197 -3
  492. data/lib/hyrax/deprecation.rb +31 -0
  493. data/lib/hyrax/engine.rb +2 -0
  494. data/lib/hyrax/form_fields.rb +17 -5
  495. data/lib/hyrax/indexer.rb +31 -2
  496. data/lib/hyrax/resource_sync/resource_list_writer.rb +3 -0
  497. data/lib/hyrax/schema.rb +15 -4
  498. data/lib/hyrax/specs/shared_specs/factories/administrative_sets.rb +12 -0
  499. data/lib/hyrax/specs/shared_specs/factories/hyrax_embargo.rb +1 -1
  500. data/lib/hyrax/specs/shared_specs/factories/hyrax_file_set.rb +13 -0
  501. data/lib/hyrax/specs/shared_specs/factories/hyrax_lease.rb +5 -1
  502. data/lib/hyrax/specs/shared_specs/factories/hyrax_work.rb +14 -0
  503. data/lib/hyrax/specs/shared_specs/simple_work.rb +41 -0
  504. data/lib/hyrax/specs/shared_specs.rb +1 -0
  505. data/lib/hyrax/transactions/collection_create.rb +2 -1
  506. data/lib/hyrax/transactions/collection_destroy.rb +1 -0
  507. data/lib/hyrax/transactions/collection_update.rb +2 -1
  508. data/lib/hyrax/transactions/container.rb +28 -0
  509. data/lib/hyrax/transactions/steps/apply_permission_template_on_update.rb +65 -0
  510. data/lib/hyrax/transactions/steps/apply_workflow_on_admin_set_change.rb +97 -0
  511. data/lib/hyrax/transactions/steps/ensure_admin_set.rb +1 -1
  512. data/lib/hyrax/transactions/steps/remove_redirect_paths.rb +35 -0
  513. data/lib/hyrax/transactions/steps/save.rb +10 -0
  514. data/lib/hyrax/transactions/steps/set_default_admin_set.rb +1 -1
  515. data/lib/hyrax/transactions/steps/sync_redirect_paths.rb +141 -0
  516. data/lib/hyrax/transactions/work_create.rb +2 -1
  517. data/lib/hyrax/transactions/work_destroy.rb +1 -0
  518. data/lib/hyrax/transactions/work_update.rb +4 -1
  519. data/lib/hyrax/version.rb +1 -1
  520. data/lib/hyrax.rb +61 -0
  521. data/lib/tasks/m3_profile_cleanup.rake +35 -0
  522. data/template.rb +4 -1
  523. metadata +313 -19
  524. data/.dassie/public/robots.txt +0 -1
  525. data/.koppie/public/robots.txt +0 -1
  526. data/app/forms/concerns/hyrax/basic_metadata_form_fields_behavior.rb +0 -39
  527. data/app/views/catalog/_thumbnail_list_collection.html.erb +0 -4
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyrax
4
+ module RequiredDataSeeders
5
+ # This class was created for use in rake tasks and db/seeds.rb. It generates
6
+ # collections that are required for all Hyrax applications.
7
+ #
8
+ # Seeders of required data are non-destructive. If the data already exists,
9
+ # it will not be replaced.
10
+ class FlexibleProfileSeeder
11
+ class << self
12
+ attr_accessor :logger
13
+
14
+ def generate_seeds(logger: Logger.new(STDOUT))
15
+ @logger = logger
16
+
17
+ logger.info("Adding required collections...")
18
+
19
+ flexible_schema = Hyrax::FlexibleSchema.first_or_create do |f|
20
+ f.profile = YAML.safe_load_file(Rails.root.join('config', 'metadata_profiles', 'm3_profile.yaml'))
21
+ end
22
+
23
+ logger.info " #{flexible_schema.title} -- FOUND OR CREATED"
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+ module Hyrax
3
+ ##
4
+ # Validates that controlled vocabulary properties contain only active
5
+ # terms from their corresponding local QA authority.
6
+ #
7
+ # Properties are matched to authorities dynamically via
8
+ # +Qa::Authorities::Local.subauthorities+, using the singularized
9
+ # authority name to match property names on the change set.
10
+ #
11
+ # Only covers local authorities (file-based and table-based).
12
+ # Remote authorities (e.g. Geonames) are out of scope.
13
+ class ControlledVocabularyValidator < ActiveModel::Validator
14
+ def validate(record)
15
+ return unless Flipflop.validate_local_controlled_vocabulary?
16
+
17
+ active_terms_by_property(record).each do |property, terms|
18
+ values = Array.wrap(record.public_send(property)).reject(&:blank?)
19
+ next if values.empty?
20
+
21
+ invalid = values.reject { |v| terms.include?(v) }
22
+ invalid.each do |v|
23
+ record.errors.add(property, "#{property.to_s.humanize} contains unrecognized value: #{v}")
24
+ end
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ ##
31
+ # @example
32
+ # # { "license" => ["http://creativecommons.org/licenses/by/4.0/", ...],
33
+ # # "resource_type" => ["Article", "Book", ...] }
34
+ #
35
+ # @return [Hash{String => Array<String>}]
36
+ def active_terms_by_property(record)
37
+ authorities = Qa::Authorities::Local.subauthorities
38
+
39
+ # { "license" => "licenses", "resource_type" => "resource_types", ... }
40
+ property_to_authority = {}.tap do |hash|
41
+ authorities.each { |name| hash[name.singularize] = name }
42
+ end
43
+
44
+ properties = record.fields.keys.map(&:to_s)
45
+
46
+ {}.tap do |result|
47
+ (properties & property_to_authority.keys).each do |property|
48
+ authority = Qa::Authorities::Local.subauthority_for(property_to_authority[property])
49
+ terms = authority.all
50
+ next if terms.empty?
51
+
52
+ result[property] = terms.filter_map { |term| term[:id] if active?(term) }
53
+ end
54
+ end
55
+ end
56
+
57
+ ##
58
+ # Terms without an +active+ field (e.g. resource_types) are
59
+ # treated as active, matching QA's +FileBasedAuthority#all+ behavior.
60
+ def active?(term)
61
+ term.fetch(:active, true) != false
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyrax
4
+ # Validates the `redirects` attribute on a work or collection. Runs only
5
+ # when the redirects feature is fully enabled (config + Flipflop).
6
+ #
7
+ # See documentation/redirects.md for the validation rules.
8
+ class RedirectValidator < ActiveModel::EachValidator
9
+ # Allow-list per RFC 3986 path chars: unreserved + sub-delims + ":" + "@" + "/"
10
+ # plus pct-encoded "%XX". Rejects quotes, backslashes, angle brackets, pipes,
11
+ # braces, control chars, whitespace, "?", and "#" — anything Rails routing
12
+ # would refuse or that would be unsafe to round-trip through a URL.
13
+ PATH_CHAR = %r{[A-Za-z0-9\-._~!$&'()*+,;=:@/]|%[0-9A-Fa-f]{2}}.freeze
14
+ PATH_FORMAT = %r{\A/(?:#{PATH_CHAR})+\z}.freeze
15
+
16
+ # Override `validate` so we can short-circuit before ActiveModel calls
17
+ # `record.read_attribute_for_validation`, which would crash on records
18
+ # that don't have the `redirects` attribute.
19
+ #
20
+ # Two guards, each catching a distinct case:
21
+ # 1. config + Flipflop — the runtime feature gate. Skips validation when
22
+ # the feature isn't actively in use.
23
+ # 2. record_supports_redirects? — the structural gate. Catches the case
24
+ # where both feature gates are on but the property wasn't added
25
+ def validate(record)
26
+ return unless Hyrax.config.redirects_active?
27
+ return unless record_supports_redirects?(record)
28
+ super
29
+ end
30
+
31
+ def validate_each(record, attribute, entries)
32
+ return if entries.blank?
33
+
34
+ validate_each_entry(record, attribute, entries)
35
+ validate_intra_record_uniqueness(record, attribute, entries)
36
+ validate_global_uniqueness(record, attribute, entries)
37
+ validate_at_most_one_display_url(record, attribute, entries)
38
+ end
39
+
40
+ private
41
+
42
+ # Entries are persisted hashes, but the form-render path may pass
43
+ # Hyrax::Redirect presenter instances. Both shapes are acceptable.
44
+ def path_for(entry)
45
+ return entry.path if entry.respond_to?(:path)
46
+ return entry['path'] || entry[:path] if entry.respond_to?(:[])
47
+ nil
48
+ end
49
+
50
+ # Returns nil when the flag is absent, otherwise a real boolean.
51
+ def display_url_for(entry)
52
+ return ActiveModel::Type::Boolean.new.cast(entry.is_display_url) if entry.respond_to?(:is_display_url)
53
+ if entry.respond_to?(:[])
54
+ return ActiveModel::Type::Boolean.new.cast(entry['is_display_url']) if entry.key?('is_display_url')
55
+ return ActiveModel::Type::Boolean.new.cast(entry[:is_display_url]) if entry.key?(:is_display_url)
56
+ end
57
+ nil
58
+ end
59
+
60
+ def validate_each_entry(record, attribute, entries)
61
+ entries.each do |entry|
62
+ path = path_for(entry)
63
+ if path.blank?
64
+ record.errors.add(attribute, message_for(:blank))
65
+ elsif !PATH_FORMAT.match?(path)
66
+ record.errors.add(attribute, message_for(:invalid_format, path: path))
67
+ elsif reserved_prefix?(path)
68
+ record.errors.add(attribute, message_for(:reserved_prefix, path: path))
69
+ end
70
+ end
71
+ end
72
+
73
+ def reserved_prefix?(path)
74
+ normalized = normalized_path(path)
75
+ Hyrax.config.reserved_redirect_prefixes.any? do |prefix|
76
+ normalized == prefix || normalized.start_with?("#{prefix}/")
77
+ end
78
+ end
79
+
80
+ def validate_intra_record_uniqueness(record, attribute, entries)
81
+ grouped = entries.each_with_object({}) do |entry, acc|
82
+ path = path_for(entry)
83
+ next if path.blank?
84
+ canonical = normalized_path(path)
85
+ next if canonical.blank?
86
+ (acc[canonical] ||= []) << path
87
+ end
88
+ grouped.each_value do |paths|
89
+ next unless paths.size > 1
90
+ record.errors.add(attribute, message_for(:intra_record_duplicate, path: paths.first))
91
+ end
92
+ end
93
+
94
+ def validate_global_uniqueness(record, attribute, entries)
95
+ except_id = record.try(:id)
96
+ entries.each do |entry|
97
+ path = path_for(entry)
98
+ next if path.blank?
99
+ next unless Hyrax::RedirectsLookup.taken?(normalized_path(path), except_id: except_id)
100
+ record.errors.add(attribute, message_for(:already_taken, path: path))
101
+ end
102
+ end
103
+
104
+ def normalized_path(path)
105
+ Hyrax::RedirectPathNormalizer.call(path)
106
+ end
107
+
108
+ def validate_at_most_one_display_url(record, attribute, entries)
109
+ display_url_count = entries.count { |entry| display_url_for(entry) }
110
+ return if display_url_count <= 1
111
+ record.errors.add(attribute, message_for(:multiple_display_url))
112
+ end
113
+
114
+ def message_for(key, **interpolations)
115
+ I18n.t(key, scope: 'errors.messages.redirect', **interpolations)
116
+ end
117
+
118
+ # Reform forms wrap the underlying resource and use method_missing to
119
+ # forward attribute reads. We can't just call `record.respond_to?(:redirects)`
120
+ # because Reform's method_missing returns truthy for missing methods.
121
+ # Probe the actual underlying resource through the form's `__getobj__`
122
+ # (Reform's accessor for the wrapped object) when present.
123
+ def record_supports_redirects?(record)
124
+ target = record.respond_to?(:__getobj__) ? record.__getobj__ : record
125
+ target.respond_to?(:redirects)
126
+ end
127
+ end
128
+ end
@@ -1,10 +1,10 @@
1
1
  <% model = document.hydra_model %>
2
2
  <div class="col-md-3">
3
3
  <% if model == Hyrax::PcdmCollection || model < Hyrax::PcdmCollection %>
4
- <%= document_presenter(document)&.thumbnail&.thumbnail_tag({ alt: document.title_or_label }, { suppress_link: true }) %>
4
+ <%= document_presenter(document)&.thumbnail&.thumbnail_tag({ alt: thumbnail_alt_text_for(document, block_name: 'default_collection_image_text') }, { suppress_link: true }) %>
5
5
  <% else %>
6
6
  <div class="list-thumbnail">
7
- <%= document_presenter(document)&.thumbnail&.thumbnail_tag(alt: document.title_or_label) %>
7
+ <%= document_presenter(document)&.thumbnail&.thumbnail_tag(alt: thumbnail_alt_text_for(document)) %>
8
8
  </div>
9
9
  <% end %>
10
10
  </div>
@@ -0,0 +1 @@
1
+ <%= render('shared/schema_version', f: f) if f.object.flexible? %>
@@ -1,2 +1,24 @@
1
- <%= f.input :title %>
2
- <%= f.input :description, as: :text %>
1
+ <div id="base-terms">
2
+ <% f.object.primary_terms.each do |term| %>
3
+ <% next if term == :contexts %>
4
+ <%= f.input term %>
5
+ <% end %>
6
+ </div>
7
+ <% if Hyrax.config.flexible? && Hyrax.config.admin_set_class.new.respond_to?(:contexts) %>
8
+ <% blank_option = f.object.model.new_record ? false : t('hyrax.admin.admin_sets.form.contexts.none') %>
9
+ <%= f.input :contexts, collection: Hyrax::FlexibleSchema.last.context_select, include_blank: blank_option, input_html: { multiple: true } %>
10
+ <% end %>
11
+ <% if f.object.display_additional_fields? %>
12
+ <%= link_to t('hyrax.collection.form.additional_fields'),
13
+ '#extended-terms',
14
+ class: 'btn btn-secondary additional-fields',
15
+ data: { toggle: 'collapse' },
16
+ role: "button",
17
+ 'aria-expanded'=> "false",
18
+ 'aria-controls'=> "extended-terms" %>
19
+ <div id="extended-terms" class='collapse'>
20
+ <% f.object.secondary_terms.each do |term| %>
21
+ <%= f.input term %>
22
+ <% end %>
23
+ </div>
24
+ <% end %>
@@ -9,7 +9,7 @@
9
9
  <td>
10
10
  <div class="media">
11
11
  <%= link_to [main_app, document], "class" => "media-left", "aria-hidden" => "true" do %>
12
- <%= document_presenter(document)&.thumbnail&.thumbnail_tag({ class: "d-none d-md-block file_listing_thumbnail" }, { suppress_link: true }) %>
12
+ <%= document_presenter(document)&.thumbnail&.thumbnail_tag({ class: "d-none d-md-block file_listing_thumbnail", alt: thumbnail_alt_text_for(document) }, { suppress_link: true }) %>
13
13
  <% end %>
14
14
  <div class="media-body">
15
15
  <p class="media-heading">
@@ -11,7 +11,7 @@
11
11
  <div class="col-md-2">
12
12
  <% if has_thumbnail? @presenter.solr_document %>
13
13
  <div class="document-thumbnail">
14
- <%= render_thumbnail_tag(@presenter.solr_document, {}, { suppress_link: true }) %>
14
+ <%= render_thumbnail_tag(@presenter.solr_document, { alt: thumbnail_alt_text_for(@presenter.solr_document, block_name: 'default_collection_image_text') }, { suppress_link: true }) %>
15
15
  </div>
16
16
  <% else %>
17
17
  <span class="fa fa-sitemap collection-icon-search" aria-hidden="true"></span>
@@ -0,0 +1,42 @@
1
+ <%# frozen_string_literal: true %>
2
+ <% if @analytics_error %>
3
+ <div class="alert alert-info" role="alert">
4
+ <div class="d-flex">
5
+ <div class="mr-3">
6
+ <i class="fa fa-info-circle fa-2x text-info" aria-hidden="true"></i>
7
+ </div>
8
+ <div class="flex-fill">
9
+ <h5 class="alert-heading mb-2">Analytics Setup Required</h5>
10
+ <p class="mb-2"><%= @analytics_error[:message] %></p>
11
+
12
+ <% if @analytics_error[:troubleshooting_steps].present? %>
13
+ <div class="mt-3">
14
+ <% @analytics_error[:troubleshooting_steps].each_with_index do |step, index| %>
15
+ <div class="mb-2">
16
+ <span class="badge badge-primary mr-2"><%= index + 1 %></span>
17
+ <%= raw(step) %>
18
+ </div>
19
+ <% end %>
20
+ </div>
21
+ <% end %>
22
+
23
+ <div class="mt-3">
24
+ <% if @analytics_error[:documentation_url].present? %>
25
+ <a href="<%= @analytics_error[:documentation_url] %>" target="_blank" rel="noopener noreferrer" class="btn btn-primary btn-sm mr-2">
26
+ Setup Guide
27
+ </a>
28
+ <% end %>
29
+ <button class="btn btn-outline-secondary btn-sm" type="button" data-toggle="collapse" data-target="#technicalDetails" aria-expanded="false" aria-controls="technicalDetails">
30
+ Technical Details
31
+ </button>
32
+ </div>
33
+
34
+ <div class="collapse mt-3" id="technicalDetails">
35
+ <div class="alert alert-light">
36
+ <small><%= @analytics_error[:details] %></small>
37
+ </div>
38
+ </div>
39
+ </div>
40
+ </div>
41
+ </div>
42
+ <% end %>
@@ -7,11 +7,12 @@
7
7
  <div class="row">
8
8
  <div class="col-sm-12">
9
9
  <div class="collection-reports">
10
-
11
- <% if Hyrax.config.analytics_reporting? %>
12
10
  <div class="card">
13
- <div class="card-header"><%= t('.repo_summary') %> <b><%= pluralize(Collection.count, "collection") %></b>, <%= t('.repo_summary_2') %> <b><%= @pageviews.all %> <%= t('.views') %></b> <%= t('.and') %> <b><%= @downloads.all %> <%= t('.downloads') %></b>.</div>
14
- <div class="card-body">
11
+ <%= render 'hyrax/admin/analytics/analytics_error' %>
12
+ <% unless @analytics_error %>
13
+ <% if Hyrax.config.analytics_reporting? %>
14
+ <div class="card-header"><%= t('.repo_summary') %> <b><%= pluralize(Collection.count, "collection") %></b>, <%= t('.repo_summary_2') %> <b><%= @pageviews.all %> <%= t('.views') %></b> <%= t('.and') %> <b><%= @downloads.all %> <%= t('.downloads') %></b>.</div>
15
+ <div class="card-body">
15
16
 
16
17
  <div class="row text-center">
17
18
  <div class="nav nav-pills btn-group" role="group">
@@ -58,13 +59,14 @@
58
59
  </div>
59
60
  </div>
60
61
  <p class="text-center"><%= t('.report_generated_on') %> <b><%= Time.current %></b>.</p>
61
- </div>
62
62
  </div>
63
- <% else %>
64
- <div class="alert alert-warning" role="alert">
65
- <%= t('.enable_analytics') %>
66
63
  </div>
64
+ <% else %>
65
+ <div class="alert alert-warning" role="alert">
66
+ <%= t('.enable_analytics') %>
67
+ </div>
68
+ <% end %>
67
69
  <% end %>
68
- </div>
69
70
  </div>
70
71
  </div>
72
+ </div>
@@ -9,69 +9,72 @@
9
9
  <div class="work-reports">
10
10
 
11
11
  <div class="card">
12
- <% if Hyrax.config.analytics_reporting? %>
13
- <% if current_user.ability.admin? %>
14
- <div class="card-header"><b><%= @works_count %> <%= t('.works') %></b> <%= t('.repo_summary') %> <b><%= @pageviews.all if @pageviews %> <%= t('.views') %></b> <%= t('.and') %> <b><%= @downloads.all if @downloads %> <%= t('.downloads') %></b>.</div>
15
- <% else %>
16
- <div class="card-header"><%= t('.access_to') %> <b><%= @works_count %> <%= t('.works') %></b>.</div>
17
- <% end %>
18
- <div class="card-body">
19
- <% if current_user.ability.admin? %>
20
- <div class="row text-center">
21
- <div class="nav nav-pills btn-group" role="group">
22
- <% if params[:start_date] %>
23
- <a button id='summary-btn' class="btn btn-secondary nav-link" type="button" href="#summary" data-toggle="pill">
24
- <% else %>
25
- <a button id='summary-btn' class="btn btn-primary nav-link" type="button" href="#summary" data-toggle="pill">
26
- <% end %>
27
- <%= t('.summary') %>
28
- </a>
29
- <a button id='monthly-btn' class="btn btn-secondary nav-link" type="button" href="#monthly" data-toggle="pill">
30
- <%= t('.monthly') %>
31
- </a>
32
- <% if params[:start_date] %>
33
- <a button id='range-btn' class="btn btn-primary nav-link" type="button" href="#custom-range" data-toggle="pill">
12
+ <%= render 'hyrax/admin/analytics/analytics_error' %>
13
+ <% unless @analytics_error %>
14
+ <% if Hyrax.config.analytics_reporting? %>
15
+ <% if current_user.ability.admin? %>
16
+ <div class="card-header"><b><%= @works_count %> <%= t('.works') %></b> <%= t('.repo_summary') %> <b><%= @pageviews.all if @pageviews %> <%= t('.views') %></b> <%= t('.and') %> <b><%= @downloads.all if @downloads %> <%= t('.downloads') %></b>.</div>
17
+ <% else %>
18
+ <div class="card-header"><%= t('.access_to') %> <b><%= @works_count %> <%= t('.works') %></b>.</div>
19
+ <% end %>
20
+ <div class="card-body">
21
+ <% if current_user.ability.admin? %>
22
+ <div class="row text-center">
23
+ <div class="nav nav-pills btn-group" role="group">
24
+ <% if params[:start_date] %>
25
+ <a button id='summary-btn' class="btn btn-secondary nav-link" type="button" href="#summary" data-toggle="pill">
26
+ <% else %>
27
+ <a button id='summary-btn' class="btn btn-primary nav-link" type="button" href="#summary" data-toggle="pill">
28
+ <% end %>
29
+ <%= t('.summary') %>
30
+ </a>
31
+ <a button id='monthly-btn' class="btn btn-secondary nav-link" type="button" href="#monthly" data-toggle="pill">
32
+ <%= t('.monthly') %>
33
+ </a>
34
+ <% if params[:start_date] %>
35
+ <a button id='range-btn' class="btn btn-primary nav-link" type="button" href="#custom-range" data-toggle="pill">
36
+ <% else %>
37
+ <a button id='range-btn' class="btn btn-secondary nav-link" type="button" href="#custom-range" data-toggle="pill">
38
+ <% end %>
39
+ <%= t('.custom_range') %>
40
+ </a>
41
+ </div>
42
+ </div>
43
+ <br>
44
+ <div class="tab-content">
45
+ <% if params[:start_date] %>
46
+ <div class="tab-pane" id="summary">
47
+ <% else %>
48
+ <div class="tab-pane active" id="summary">
49
+ <% end %>
50
+ <%= render "summary" %>
51
+ </div>
52
+ <div class="tab-pane" id="monthly">
53
+ <%= render "monthly_summary" %>
54
+ </div>
55
+ <% if params[:start_date] %>
56
+ <div class="tab-pane active" id="custom-range">
34
57
  <% else %>
35
- <a button id='range-btn' class="btn btn-secondary nav-link" type="button" href="#custom-range" data-toggle="pill">
58
+ <div class="tab-pane" id="custom-range">
36
59
  <% end %>
37
- <%= t('.custom_range') %>
38
- </a>
39
- </div>
40
- </div>
41
- <br>
42
- <div class="tab-content">
43
- <% if params[:start_date] %>
44
- <div class="tab-pane" id="summary">
45
- <% else %>
46
- <div class="tab-pane active" id="summary">
47
- <% end %>
48
- <%= render "summary" %>
49
- </div>
50
- <div class="tab-pane" id="monthly">
51
- <%= render "monthly_summary" %>
60
+ <%= render "hyrax/admin/analytics/date_range_form", redirect_path: hyrax.admin_analytics_work_reports_path %>
61
+ <%= render "custom_range" %>
62
+ </div>
63
+ </div>
64
+ <% end %>
52
65
  </div>
53
- <% if params[:start_date] %>
54
- <div class="tab-pane active" id="custom-range">
55
- <% else %>
56
- <div class="tab-pane" id="custom-range">
57
- <% end %>
58
- <%= render "hyrax/admin/analytics/date_range_form", redirect_path: hyrax.admin_analytics_work_reports_path %>
59
- <%= render "custom_range" %>
60
- </div>
61
66
  </div>
62
- <% end %>
63
- </div>
64
- </div>
65
- <p class="text-center"><%= t('.report_generated_on') %> <b><%= Time.zone.today.strftime("%B %d, %Y") %></b></p>
67
+ <p class="text-center"><%= t('.report_generated_on') %> <b><%= Time.zone.today.strftime("%B %d, %Y") %></b></p>
66
68
 
67
- </div>
69
+ </div>
68
70
 
69
- </div>
70
- <% else %>
71
- <div class="alert alert-warning" role="alert">
72
- <%= t('.enable_analytics') %>
73
- </div>
74
- <% end %>
71
+ </div>
72
+ <% else %>
73
+ <div class="alert alert-warning" role="alert">
74
+ <%= t('.enable_analytics') %>
75
+ </div>
76
+ <% end %>
77
+ <% end %>
75
78
  </div>
76
79
  </div>
77
80
  </div>
@@ -32,7 +32,7 @@
32
32
  <td class="status">
33
33
  <span class="badge badge-<%= @feature_set.status(feature) -%>"><%= @feature_set.status(feature) -%></span>
34
34
  </td>
35
- <td class="name"><%= feature.name.humanize -%></td>
35
+ <td class="name"><%= feature.title || feature.name.humanize -%></td>
36
36
  <td class="description"><%= feature.description -%></td>
37
37
 
38
38
  <% @feature_set.strategies.each do |strategy| -%>
@@ -0,0 +1,20 @@
1
+ <div id="myModal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
2
+ <div class="modal-dialog" role="document">
3
+ <%= form_tag(hyrax.import_admin_metadata_profiles_path, :multipart => true, :class => "modal-content") do %>
4
+ <div class="modal-header">
5
+ <h2 class="modal-title"><%= t(:'helpers.action.hyrax_metadata_profile.import') %></h2>
6
+ <button type="button" class="close" data-dismiss="modal" aria-label="<%= t('hyrax.dashboard.heading_actions.close') %>"><span aria-hidden="true">&times;</span></button>
7
+ </div>
8
+ <div class="modal-body">
9
+ <% unless @metadata_profiles.empty? %>
10
+ <p><%= t(:'helpers.action.hyrax_metadata_profile.hint') %></p>
11
+ <% end %>
12
+ <%= file_field_tag :file, class: 'form-control-file' %>
13
+ </div>
14
+ <div class="modal-footer">
15
+ <button type="button" class="btn btn-secondary" data-dismiss="modal"><%= t('hyrax.dashboard.heading_actions.close') %></button>
16
+ <%= submit_tag t(:'helpers.action.hyrax_metadata_profile.submit'), name: nil, class: "btn btn-primary" %>
17
+ </div>
18
+ <% end %>
19
+ </div>
20
+ </div>
@@ -0,0 +1,54 @@
1
+ <% provide :page_title, t(:'hyrax.dashboard.metadata_profiles') %>
2
+
3
+ <% provide :page_header do %>
4
+ <h1><span class="fa fa-table" aria-hidden="true"></span> <%= t(:'hyrax.admin.sidebar.metadata_profiles') %></h1>
5
+ <div class="pull-right">
6
+ <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#myModal">
7
+ <span class="fa fa-upload" aria-hidden="true"></span>
8
+ <%= t(:'helpers.action.hyrax_metadata_profile.import_metadata_profile') %>
9
+ </button>
10
+ </div>
11
+ <% end %>
12
+
13
+ <div class="panel panel-default">
14
+ <div class="card-body">
15
+ <% if @metadata_profiles.present? %>
16
+ <div class="table-responsive">
17
+ <table class="table table-striped datatable">
18
+ <thead>
19
+ <tr>
20
+ <th scope="col">Schema Version</th>
21
+ <th scope="col">Profile Version</th>
22
+ <th scope="col">Profile Type</th>
23
+ <th scope="col">Created At</th>
24
+ <th scope="col">Actions</th>
25
+ </tr>
26
+ </thead>
27
+ <tbody>
28
+ <% @metadata_profiles.order("updated_at DESC").each do |hyrax_metadata_profile| %>
29
+ <tr>
30
+
31
+ <!-- TODO: fix show pgs -->
32
+ <td><%= hyrax_metadata_profile.schema_version %></td>
33
+ <td><%= hyrax_metadata_profile.id.to_f %></td>
34
+ <td><%= hyrax_metadata_profile.metadata_profile_type %></td>
35
+ <td><%= hyrax_metadata_profile.created_at.strftime("%b %d, %Y") %></td>
36
+ <th><%= link_to raw('<span class="fa fa-download"></span>'), hyrax.admin_metadata_profile_export_path(hyrax_metadata_profile), target: "_blank" %></th>
37
+ </tr>
38
+ <% end %>
39
+ </tbody>
40
+ </table>
41
+
42
+ <%= page_entries_info @metadata_profiles %><br />
43
+ <%= paginate(@metadata_profiles, param_name: :metadata_profile_entries_page) %>
44
+
45
+ </div>
46
+ <% else %>
47
+ <p>No Metadata Schema Profiles have been created.</p>
48
+ <% end %>
49
+ </div>
50
+ </div>
51
+
52
+
53
+ <!-- Modal -->
54
+ <%= render 'import_modal' %>
@@ -1,21 +1,4 @@
1
- <%= presenter.attribute_to_html(:alternative_title, html_dl: true) %>
2
- <%= presenter.attribute_to_html(:abstract, html_dl: true) %>
3
- <%= presenter.attribute_to_html(:date_modified, label: t('hyrax.base.show.last_modified'), html_dl: true) %>
4
- <%= presenter.attribute_to_html(:creator, render_as: :faceted, html_dl: true) %>
5
- <%= presenter.attribute_to_html(:contributor, render_as: :faceted, html_dl: true) %>
6
- <%= presenter.attribute_to_html(:subject, render_as: :faceted, html_dl: true) %>
7
- <%= presenter.attribute_to_html(:publisher, render_as: :faceted, html_dl: true) %>
8
- <%= presenter.attribute_to_html(:bibliographic_citation, html_dl: true) %>
9
- <%= presenter.attribute_to_html(:language, render_as: :faceted, html_dl: true) %>
10
- <%= presenter.attribute_to_html(:identifier, render_as: :linked, search_field: 'identifier_tesim', html_dl: true) %>
11
- <%= presenter.attribute_to_html(:keyword, render_as: :faceted, html_dl: true) %>
12
- <%= presenter.attribute_to_html(:date_created, render_as: :linked, search_field: 'date_created_tesim', html_dl: true) %>
13
- <%= presenter.attribute_to_html(:based_near_label, html_dl: true) %>
14
- <%= presenter.attribute_to_html(:related_url, render_as: :external_link, html_dl: true) %>
15
- <%= presenter.attribute_to_html(:resource_type, render_as: :faceted, html_dl: true) %>
16
- <%= presenter.attribute_to_html(:source, html_dl: true) %>
17
- <%= presenter.attribute_to_html(:extent, html_dl: true) %>
18
- <%= presenter.attribute_to_html(:rights_statement, render_as: :rights_statement, html_dl: true) %>
19
- <%= presenter.attribute_to_html(:rights_notes, html_dl: true) %>
20
- <%= presenter.attribute_to_html(:access_right, html_dl: true) %>
21
- <%= presenter.attribute_to_html(:license, render_as: :license, html_dl: true) %>
1
+ <% view_options_for(presenter).each do |field, options| %>
2
+ <% view_options = conform_options(field, options) %>
3
+ <%= presenter.attribute_to_html(conform_field(field, options), view_options) if field_visible?(view_options, presenter) %>
4
+ <% end %>
@@ -1,4 +1,5 @@
1
1
  <div class="citations">
2
+ <%= render 'hyrax/shared/copy_permalink', presenter: presenter %>
2
3
  <% if Hyrax.config.citations? %>
3
4
  <%= link_to t(".citations"), hyrax.citations_work_path(presenter), id: 'citations', class: 'btn btn-secondary btn-sm mr-2' %>
4
5
  <% end %>
@@ -5,7 +5,8 @@
5
5
  <table class="table table-bordered">
6
6
  <tr>
7
7
  <th><%= t('.table_title_user') %></th>
8
- <th><div class="col-sm-10"><%= t('.table_title_access') %></div></th>
8
+ <th><%= t('.table_title_access') %></th>
9
+ <th><%= t('.table_title_action') %></th>
9
10
  </tr>
10
11
  <tr id="file_permissions">
11
12
  <td>
@@ -1 +1 @@
1
- <%= document_presenter(node)&.thumbnail&.thumbnail_tag({ class: 'thumbnail-inner mw-100', 'alt': "Thumbnail image for #{node.title[0]}" }, {}) %>
1
+ <%= document_presenter(node)&.thumbnail&.thumbnail_tag({ class: 'thumbnail-inner mw-100', alt: node.alt_text_for_view }, {}) %>