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
data/.rubocop.yml CHANGED
@@ -11,6 +11,7 @@ AllCops:
11
11
  DisplayCopNames: true
12
12
  Exclude:
13
13
  - 'db/**/*'
14
+ - '.dassie/db/**/*'
14
15
  - 'script/**/*'
15
16
  - 'spec/test_app_templates/**/*'
16
17
  - 'vendor/**/*'
data/CONTAINERS.md CHANGED
@@ -73,6 +73,8 @@ Let's break down the above command:
73
73
 
74
74
  _**Note:**_ The `bundle exec rspec` portion of the command runs the whole test suite. See the [rspec command documentation](https://github.com/rspec/rspec-core#the-rspec-command) for how to refine your test runs.
75
75
 
76
+ **If you get "You have already activated rspec-support X, but your Gemfile requires rspec-support Y"** when running specs, you are not using the engine's bundle. Always use `bundle exec rspec` (never plain `rspec`). If you shell into the container and run from `/app/samvera/hyrax-engine`, force the engine's Gemfile: `BUNDLE_GEMFILE=Gemfile bundle exec rspec ./spec/path/to/spec.rb`.
77
+
76
78
  #### The Docker Container Named "web"
77
79
 
78
80
  As a developer, you may need to run commands against the Hyrax-based application and/or the Hyrax engine. Examples
data/Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- ARG DEBIAN_VERSION=bookworm
1
+ ARG DEBIAN_VERSION=trixie
2
2
  ARG RUBY_VERSION=3.3
3
3
 
4
4
  FROM ruby:$RUBY_VERSION-$DEBIAN_VERSION AS hyrax-base
@@ -8,11 +8,14 @@ RUN apt-get update && \
8
8
  apt-get install -y --no-install-recommends \
9
9
  acl \
10
10
  build-essential \
11
+ clamav-daemon \
12
+ clamdscan \
11
13
  curl \
12
14
  exiftool \
13
15
  ffmpeg \
14
16
  ghostscript \
15
17
  git \
18
+ imagemagick \
16
19
  less \
17
20
  libgsf-1-dev \
18
21
  libimagequant-dev \
@@ -53,29 +56,9 @@ RUN apt-get update && \
53
56
  apt-get clean && \
54
57
  rm -rf /var/lib/apt/lists/* && \
55
58
  ln -s /usr/lib/*-linux-gnu/libjemalloc.so.2 /usr/lib/libjemalloc.so.2 && \
59
+ mkdir -p /var/run/clamav && chown clamav:clamav /var/run/clamav && \
56
60
  echo "******** Packages Installed *********"
57
61
 
58
- RUN bash -x -c "\
59
- if [ $(dpkg --print-architecture) = 'amd64' ]; then \
60
- wget https://github.com/ImageMagick/ImageMagick/releases/download/7.1.1-47/ImageMagick-82572af-gcc-x86_64.AppImage -O magick \
61
- && chmod a+x magick \
62
- && ./magick --appimage-extract \
63
- && mv squashfs-root/usr/etc/ImageMagick* /etc \
64
- && rm -rf squashfs-root/usr/share/doc \
65
- && cp -rv squashfs-root/usr/* /usr/local \
66
- && rm -rf magick squashfs-root ; \
67
- else \
68
- wget https://github.com/ImageMagick/ImageMagick/archive/refs/tags/7.1.1-47.tar.gz \
69
- && tar xf 7.1.1-47.tar.gz \
70
- && cd ImageMagick* \
71
- && ./configure \
72
- && make install \
73
- && ldconfig /usr/local/lib \
74
- && cd $OLDPWD \
75
- && rm -rf 7.1.1-47.tar.gz ImageMagick* ; \
76
- fi \
77
- && identify -version"
78
-
79
62
  RUN setfacl -d -m o::rwx /usr/local/bundle && \
80
63
  gem update --silent --system
81
64
 
@@ -147,6 +130,10 @@ ENV BUILD_GITSHA=$BUILD_GITSHA \
147
130
 
148
131
  FROM hyrax-worker-base AS hyrax-engine-dev
149
132
 
133
+ # Reduce memory requirements
134
+ RUN echo "ConcurrentDatabaseReload no" >> /etc/clamav/clamd.conf && \
135
+ sed -i 's/\(TestDatabases\).*/\1 no/' /etc/clamav/freshclam.conf
136
+
150
137
  USER app
151
138
  ARG BUNDLE_WITHOUT=
152
139
  ENV HYRAX_ENGINE_PATH=/app/samvera/hyrax-engine
data/Gemfile CHANGED
@@ -21,5 +21,4 @@ group :development, :test do
21
21
  gem 'ruby-prof', require: false
22
22
  gem 'semaphore_test_boosters'
23
23
  gem 'simplecov', require: false
24
- gem 'timecop'
25
24
  end
data/Gemfile.allinson ADDED
@@ -0,0 +1,2 @@
1
+ # Use dedicated lock files for dassie/koppie to avoid gem mismatches
2
+ eval_gemfile 'Gemfile'
data/README.md CHANGED
@@ -3,8 +3,7 @@
3
3
  ![Samvera's Hyrax Logo](https://raw.githubusercontent.com/samvera/hyrax/gh-pages/assets/images/hyrax_logo_horizontal_white_background.png)
4
4
 
5
5
  Code: [![Version](https://badge.fury.io/rb/hyrax.png)](http://badge.fury.io/rb/hyrax)
6
- [![CircleCI](https://circleci.com/gh/samvera/hyrax.svg?style=svg)](https://circleci.com/gh/samvera/hyrax)
7
- [![Code Climate](https://codeclimate.com/github/samvera/hyrax/badges/gpa.svg)](https://codeclimate.com/github/samvera/hyrax)
6
+ [![Lint Build Test](https://github.com/samvera/hyrax/actions/workflows/lint-build-test.yml/badge.svg)](https://github.com/samvera/hyrax/actions/workflows/lint-build-test.yml)
8
7
 
9
8
  Docs: [![Documentation Status](https://inch-ci.org/github/samvera/hyrax.svg?branch=master)](https://inch-ci.org/github/samvera/hyrax)
10
9
  [![API Docs](http://img.shields.io/badge/API-docs-blue.svg)](http://rubydoc.info/gems/hyrax)
@@ -23,6 +23,8 @@ module Hyrax
23
23
  # @see IngestJob
24
24
  # @todo create a job to monitor the temp directory (or in a multi-worker system, directories!) to prune old files that have made it into the repo
25
25
  def ingest_file(io)
26
+ io.use_valkyrie = false # we are in the actors, we need af objects
27
+
26
28
  Hydra::Works::AddFileToFileSet.call(file_set,
27
29
  io,
28
30
  relation,
@@ -123,7 +123,7 @@ module Hyrax
123
123
 
124
124
  # uses create! because object must be persisted to serialize for jobs
125
125
  def wrapper!(file:, relation:)
126
- JobIoWrapper.create_with_varied_file_handling!(user: user, file: file, relation: relation, file_set: file_set)
126
+ JobIoWrapper.create_with_varied_file_handling!(user: user, file: file, relation: relation, file_set: file_set, use_valkyrie: false)
127
127
  end
128
128
 
129
129
  # For the label, use the original_filename or original_name if it's there.
@@ -22,24 +22,25 @@ Hyrax = {
22
22
  this.sidebar();
23
23
  this.batchSelect();
24
24
  this.internationalizationHelper();
25
+ this.fileSetEditor();
25
26
  },
26
27
 
27
28
  // The AdminSet edit page
28
29
  adminSetEditor: function() {
29
30
  var AdminSetControls = require('hyrax/admin/admin_set_controls');
30
- var controls = new AdminSetControls($('#admin-set-controls'));
31
+ new AdminSetControls($('#admin-set-controls'));
31
32
  },
32
33
 
33
34
  // The collectionType edit page
34
35
  collectionTypeEditor: function() {
35
36
  var CollectionTypeControls = require('hyrax/admin/collection_type_controls');
36
- var controls = new CollectionTypeControls($('#collection-types-controls'));
37
+ new CollectionTypeControls($('#collection-types-controls'));
37
38
  },
38
39
 
39
40
  // The Collection edit page
40
41
  collectionEditor: function() {
41
42
  var CollectionControls = require('hyrax/collections/editor');
42
- var controls = new CollectionControls($('#collection-edit-controls'));
43
+ new CollectionControls($('#collection-edit-controls'));
43
44
  },
44
45
 
45
46
  // Collections v2 - collections related js should (over time) be moved here
@@ -52,7 +53,7 @@ Hyrax = {
52
53
  // Collection types
53
54
  collectionTypes: function() {
54
55
  var CollectionTypes = require('hyrax/collection_types');
55
- var collection_types = new CollectionTypes($('.collection-types-wrapper'))
56
+ new CollectionTypes($('.collection-types-wrapper'));
56
57
  },
57
58
 
58
59
  collectionUtilities: function() {
@@ -82,13 +83,22 @@ Hyrax = {
82
83
 
83
84
  // The work edit page
84
85
  workEditor: function () {
85
- var element = $("[data-behavior='work-form']")
86
+ var element = $("[data-behavior='work-form']");
86
87
  if (element.length > 0) {
87
88
  var Editor = require('hyrax/editor');
88
89
  new Editor(element).init();
89
90
  }
90
91
  },
91
92
 
93
+ // The file set edit page
94
+ fileSetEditor: function () {
95
+ var element = $("[data-behavior='file-set-form']");
96
+ if (element.length > 0) {
97
+ var Editor = require('hyrax/editor');
98
+ new Editor(element).init();
99
+ }
100
+ },
101
+
92
102
  // Popover help modals. Used on the user profile page.
93
103
  popovers: function () {
94
104
  $("a[data-toggle=popover]").popover({html: true})
@@ -119,8 +129,8 @@ Hyrax = {
119
129
  <% if Hyrax.config.realtime_notifications? %>
120
130
  var consumer = ActionCable.createConsumer("<%= Hyrax::Engine.routes.url_helpers.notifications_endpoint_path %>");
121
131
  consumer.subscriptions.create("Hyrax::NotificationsChannel", {
122
- connected: function(data) {
123
- this.perform("update_locale", { locale: $('html').attr('lang') });
132
+ connected: function() {
133
+ this.perform("update_locale", { locale: $('html').attr('lang') });
124
134
  },
125
135
 
126
136
  received: function(data) {
@@ -154,9 +164,132 @@ Hyrax = {
154
164
 
155
165
  // Minimize/maximize the dashboard sidebar
156
166
  sidebar: function () {
157
- $('.sidebar-toggle').on('click', function() {
158
- $('.sidebar, .main-content').toggleClass('maximized')
159
- })
167
+ // Cache jQuery selectors
168
+ var $sidebar = $('.sidebar');
169
+ var $toggle = $('.sidebar-toggle');
170
+ var $mainContent = $('.main-content');
171
+ var $sidebarElements = $('.sidebar, .main-content');
172
+
173
+ var isMobileView = function() {
174
+ return $(window).width() < 992;
175
+ };
176
+
177
+ var closeSidebar = function() {
178
+ $sidebarElements.removeClass('maximized');
179
+ $toggle.attr('aria-expanded', 'false');
180
+ manageFocusTrap();
181
+ $toggle.focus();
182
+ };
183
+
184
+ var updateSidebarState = function() {
185
+ var isMobile = isMobileView();
186
+ var isMaximized = $sidebar.hasClass('maximized');
187
+
188
+ if (isMobile) {
189
+ // On mobile, ensure sidebar is collapsed
190
+ if (isMaximized) {
191
+ $sidebarElements.removeClass('maximized');
192
+ $toggle.attr('aria-expanded', 'false');
193
+ }
194
+ } else {
195
+ // On desktop, ensure sidebar is maximized
196
+ if (!isMaximized) {
197
+ $sidebarElements.addClass('maximized');
198
+ $toggle.attr('aria-expanded', 'true');
199
+ }
200
+ }
201
+ };
202
+
203
+ // Prevent keyboard focus from reaching greyed-out content
204
+ var manageFocusTrap = function() {
205
+ var isMobile = isMobileView();
206
+ var isMaximized = $mainContent.hasClass('maximized');
207
+
208
+ if (isMobile && isMaximized) {
209
+ // Set tabindex on all focusable elements in greyed-out content
210
+ $mainContent.find('a, button, input, select, textarea, [tabindex]:not([tabindex="-1"])').each(function() {
211
+ if (!$(this).attr('data-original-tabindex')) {
212
+ $(this).attr('data-original-tabindex', $(this).attr('tabindex') || '0');
213
+ $(this).attr('tabindex', '-1');
214
+ }
215
+ });
216
+ } else {
217
+ $mainContent.find('[data-original-tabindex]').each(function() {
218
+ var originalTabindex = $(this).attr('data-original-tabindex');
219
+ $(this).attr('tabindex', originalTabindex === '0' ? null : originalTabindex);
220
+ $(this).removeAttr('data-original-tabindex');
221
+ });
222
+ }
223
+ };
224
+
225
+ var toggleSidebar = function() {
226
+ var isMobile = isMobileView();
227
+ var isMaximized = $sidebar.hasClass('maximized');
228
+
229
+ $sidebarElements.toggleClass('maximized');
230
+ $toggle.attr('aria-expanded', !isMaximized);
231
+
232
+ // Manage sidebar state changes
233
+ manageFocusTrap();
234
+
235
+ // Focus management for accessibility
236
+ if (isMobile) {
237
+ if (!isMaximized) {
238
+ // Sidebar focus to first element in sidebar
239
+ var $firstFocusable = $sidebar.find('a, button, [tabindex]:not([tabindex="-1"])').first();
240
+ if ($firstFocusable.length) {
241
+ setTimeout(function() {
242
+ $firstFocusable.focus();
243
+ }, 100);
244
+ }
245
+ } else {
246
+ // Return focus to toggle button
247
+ $toggle.focus();
248
+ }
249
+ }
250
+ };
251
+
252
+ // Set initial state
253
+ updateSidebarState();
254
+ manageFocusTrap();
255
+
256
+ // Add initialized class to prevent the flash of open sidebar on mobile page load
257
+ $sidebarElements.addClass('js-initialized');
258
+
259
+ // Update state when window is resized
260
+ $(window).on('resize', function() {
261
+ updateSidebarState();
262
+ manageFocusTrap();
263
+ });
264
+
265
+ // Toggle sidebar on click
266
+ $toggle.on('click', function() {
267
+ toggleSidebar();
268
+ });
269
+
270
+ // Toggle sidebar on keyboard press
271
+ $toggle.on('keydown', function(e) {
272
+ if (e.key === 'Enter' || e.key === ' ') {
273
+ e.preventDefault();
274
+ toggleSidebar();
275
+ }
276
+ });
277
+
278
+ // Close sidebar when clicking backdrop on mobile
279
+ $('.sidebar-backdrop').on('click', function() {
280
+ if (isMobileView()) {
281
+ closeSidebar();
282
+ }
283
+ });
284
+
285
+ // Close sidebar on Escape key when open on mobile
286
+ $(document).on('keydown', function(e) {
287
+ if (e.key === 'Escape' && isMobileView()) {
288
+ if ($sidebar.hasClass('maximized')) {
289
+ closeSidebar();
290
+ }
291
+ }
292
+ });
160
293
  },
161
294
 
162
295
  // Add and reorder files attached to works
@@ -0,0 +1,68 @@
1
+ // Initialize collection-select2 dropdowns in a targeted way
2
+ // This runs after document ready to avoid interfering with other Select2 initializations
3
+
4
+ $(document).on('turbolinks:load', function() {
5
+ // Use a longer delay to ensure controlled vocabulary Select2s are initialized first
6
+ setTimeout(initializeCollectionSelect2, 500);
7
+ });
8
+
9
+ // Also handle regular page loads (non-turbolinks)
10
+ $(document).ready(function() {
11
+ if (typeof Turbolinks === 'undefined') {
12
+ setTimeout(initializeCollectionSelect2, 500);
13
+ }
14
+ });
15
+
16
+ // Initialize on modal show events
17
+ $(document).on('shown.bs.modal', '.modal', function() {
18
+ initializeCollectionSelect2();
19
+ });
20
+
21
+ function initializeCollectionSelect2() {
22
+ // Only initialize collection-select2 elements that:
23
+ // 1. Are not already initialized
24
+ // 2. Are visible
25
+ // 3. Are specifically for collection selection (not location fields)
26
+ $('.collection-select2:visible:not(.select2-hidden-accessible)').each(function() {
27
+ var $select = $(this);
28
+
29
+ // Skip if this is inside a controlled vocabulary field (location search)
30
+ if ($select.closest('.controlled_vocabulary').length > 0) {
31
+ return;
32
+ }
33
+
34
+ var dropdownParent = $select.closest('.modal-body');
35
+ var options = {
36
+ placeholder: $select.data('placeholder') || 'Select',
37
+ allowClear: true
38
+ };
39
+
40
+ if (dropdownParent.length > 0) {
41
+ options.dropdownParent = dropdownParent;
42
+ }
43
+
44
+ $select.select2(options);
45
+ });
46
+
47
+ // Also initialize member_of_collection_ids selects that don't have collection-select2 class
48
+ $('select[name="member_of_collection_ids"]:visible:not(.select2-hidden-accessible)').each(function() {
49
+ var $select = $(this);
50
+
51
+ // Skip if already has select2 or is inside controlled vocabulary
52
+ if ($select.data('select2') || $select.closest('.controlled_vocabulary').length > 0) {
53
+ return;
54
+ }
55
+
56
+ var dropdownParent = $select.closest('.modal-body');
57
+ var options = {
58
+ placeholder: $select.data('placeholder') || 'Select',
59
+ allowClear: true
60
+ };
61
+
62
+ if (dropdownParent.length > 0) {
63
+ options.dropdownParent = dropdownParent;
64
+ }
65
+
66
+ $select.select2(options);
67
+ });
68
+ }
@@ -0,0 +1,28 @@
1
+ // Wires the "Copy permalink" button (on work and collection show pages) to
2
+ // ClipboardJS. The button ships with the button label as its `title` so a
3
+ // pre-init hover shows something sensible; we initialize a manual-trigger
4
+ // Bootstrap tooltip so the browser's native title-attribute tooltip stops
5
+ // appearing on hover. On a successful copy we swap the tooltip text to the
6
+ // "Copied!" message, show it briefly, then restore the original label.
7
+ Blacklight.onLoad(function () {
8
+ var $buttons = $('.copy-permalink-button');
9
+ if (!$buttons.length) { return; }
10
+
11
+ $buttons.tooltip({ trigger: 'manual' });
12
+
13
+ var clipboard = new Clipboard('.copy-permalink-button');
14
+
15
+ clipboard.on('success', function (e) {
16
+ var $btn = $(e.trigger);
17
+ var originalLabel = $btn.attr('data-original-title');
18
+ var successText = $btn.attr('data-success-text');
19
+
20
+ $btn.attr('data-original-title', successText).tooltip('show');
21
+
22
+ setTimeout(function () {
23
+ $btn.tooltip('hide').attr('data-original-title', originalLabel);
24
+ }, 1500);
25
+
26
+ e.clearSelection();
27
+ });
28
+ });
@@ -0,0 +1,45 @@
1
+ // Behavior for the Aliases form (see app/views/hyrax/base/_form_redirects.html.erb).
2
+ // Event-delegated handlers on document so dynamically-added rows work
3
+ // without rebinding. A sentinel on document guards against the IIFE
4
+ // running twice (Turbolinks evaluates module scripts again on some
5
+ // navigation paths in development), which would otherwise stack
6
+ // duplicate listeners and fire each handler N times per click.
7
+ (function() {
8
+ if (document.hyraxRedirectsBound) return;
9
+ document.hyraxRedirectsBound = true;
10
+
11
+ document.addEventListener('input', function(event) {
12
+ var pathInput = event.target.closest('[data-redirects-path-input]');
13
+ if (!pathInput) return;
14
+ var radioId = pathInput.getAttribute('data-redirects-display-radio');
15
+ var radio = document.getElementById(radioId);
16
+ if (radio) radio.disabled = (pathInput.value.trim() === '');
17
+ });
18
+
19
+ document.addEventListener('click', function(event) {
20
+ var removeButton = event.target.closest('[data-redirects-remove-row]');
21
+ if (removeButton) {
22
+ var row = removeButton.closest('tr');
23
+ if (row) row.parentNode.removeChild(row);
24
+ return;
25
+ }
26
+
27
+ var addButton = event.target.closest('[data-redirects-add-row]');
28
+ if (!addButton) return;
29
+ var template = document.querySelector('[data-redirects-row-template]');
30
+ var table = document.querySelector('[data-redirects-table]');
31
+ if (!template || !table) return;
32
+ var tbody = table.querySelector('tbody');
33
+ if (!tbody) return;
34
+ // Monotonic counter on the table; never recycle an index after a
35
+ // row is removed. Fallback to row count when the attribute is
36
+ // missing.
37
+ var nextIndex = parseInt(table.dataset.nextIndex, 10);
38
+ if (isNaN(nextIndex)) {
39
+ nextIndex = tbody.querySelectorAll('[data-redirects-row]').length;
40
+ }
41
+ var html = template.innerHTML.replace(/__INDEX__/g, nextIndex);
42
+ tbody.insertAdjacentHTML('beforeend', html);
43
+ table.dataset.nextIndex = String(nextIndex + 1);
44
+ });
45
+ })();
@@ -18,17 +18,37 @@ export default class RelationshipsControl {
18
18
  this.element = $(element)
19
19
  this.members = this.element.data('members')
20
20
  this.registry = new Registry(this.element.find('tbody'), paramKey, property, templateId)
21
- this.input = this.element.find(`[data-autocomplete]`)
21
+ this.input = this.element.find(`[data-autocomplete], .collection-select2`)
22
22
  this.warning = this.element.find(".message.has-warning")
23
23
  this.addButton = this.element.find("[data-behavior='add-relationship']")
24
24
  this.errors = null
25
25
  }
26
26
 
27
27
  init() {
28
+ this.ensureSelect2();
28
29
  this.bindAddButton();
29
30
  this.displayMembers();
30
31
  }
31
32
 
33
+ ensureSelect2() {
34
+ // Ensure select2 is initialized on collection-select2 dropdowns
35
+ // The global initialization should handle this, but we'll check just in case
36
+ let collectionSelect = this.input.filter('.collection-select2, select[name="member_of_collection_ids"]');
37
+ if (collectionSelect.length > 0 && !collectionSelect.hasClass('select2-hidden-accessible')) {
38
+ let dropdownParent = collectionSelect.closest('.modal-body');
39
+ let options = {
40
+ placeholder: collectionSelect.data('placeholder') || 'Select',
41
+ allowClear: true
42
+ };
43
+
44
+ if (dropdownParent.length > 0) {
45
+ options.dropdownParent = dropdownParent;
46
+ }
47
+
48
+ collectionSelect.select2(options);
49
+ }
50
+ }
51
+
32
52
  validate() {
33
53
  if (this.input.val() === "") {
34
54
  this.errors = ['ID cannot be empty.']
@@ -39,8 +39,13 @@ export default class SelectWorkType {
39
39
  // for a single work. So, given the value of 'this.type', return the appropriate
40
40
  // path.
41
41
  destination() {
42
- let admin_set_id = this.form.find('select').val()
43
42
  let url = this.form.find('input[type="radio"]:checked').data(this.type)
44
- return url + "&admin_set_id=" + admin_set_id
43
+ const select = this.form.find('select')
44
+
45
+ // Only append admin_set_id if the select exists and has a value
46
+ if (select.length && select.val()) {
47
+ url = url + "&admin_set_id=" + select.val()
48
+ }
49
+ return url
45
50
  }
46
51
  }
@@ -1,6 +1,5 @@
1
1
  //= require jquery-ui
2
2
 
3
-
4
3
  //= require select2
5
4
  //= require fixedsticky
6
5
 
@@ -45,6 +44,8 @@
45
44
  //= require hyrax/proxy_rights
46
45
  //= require hyrax/sorting
47
46
  //= require hyrax/single_use_links_manager
47
+ //= require hyrax/copy_permalink_button
48
+ //= require hyrax/redirects
48
49
  //= require hyrax/dashboard_actions
49
50
  //= require hyrax/batch
50
51
  //= require hyrax/flot_stats
@@ -73,6 +74,7 @@
73
74
  //= require hyrax/collections_v2
74
75
  //= require hyrax/collection_types
75
76
  //= require hyrax/collections_utils
77
+ //= require hyrax/collection_select
76
78
  //= require hyrax/select_collection_type
77
79
  //= require hydra-editor/hydra-editor
78
80
  //= require nestable
@@ -3,6 +3,7 @@
3
3
  padding-top: 1em;
4
4
  dt {
5
5
  color: $file-show-term-color;
6
+ break-inside: avoid;
6
7
  }
7
8
  dd {
8
9
  padding-bottom: .35em;
@@ -11,9 +11,17 @@
11
11
  left: 0;
12
12
  }
13
13
 
14
+ // Universal Viewer:
14
15
  // Show various footer, header, left and right panels on larger screens only
15
16
  @media only screen and (min-width: 640px) {
16
17
  .viewer-wrapper {
17
18
  height: 640px;
18
19
  }
20
+ }
21
+
22
+ // Clover IIIF Viewer:
23
+ // Increase the height so that thumbnails below the player are visible
24
+ // (for works with multiple audio/video files)
25
+ .viewer-wrapper.clover-viewer-wrapper {
26
+ height: 775px;
19
27
  }
@@ -66,6 +66,8 @@ body.dashboard {
66
66
  font-size: $h2-font-size;
67
67
  margin-left: $table-cell-padding-sm;
68
68
  margin-top: $input-btn-padding-y;
69
+ flex: 1 1 auto;
70
+ min-width: 0; // Prevents overflow
69
71
 
70
72
  .fa {
71
73
  color: $gray;
@@ -75,6 +77,25 @@ body.dashboard {
75
77
 
76
78
  .btn {
77
79
  margin-bottom: $input-btn-padding-y;
80
+ flex-shrink: 0; // Prevents button from shrinking
81
+ white-space: nowrap; // Prevents button text from wrapping
82
+ }
83
+
84
+ // Ensure flexbox container works on different screen sizes
85
+ .d-flex {
86
+ width: 100%;
87
+ }
88
+
89
+ @media screen and (max-width: 767px) {
90
+ h1 {
91
+ margin-left: 0;
92
+ width: 100%;
93
+ }
94
+
95
+ .btn {
96
+ width: 100%;
97
+ margin-top: 0.5rem;
98
+ }
78
99
  }
79
100
  }
80
101
 
@@ -121,7 +142,7 @@ body.dashboard {
121
142
  }
122
143
 
123
144
  .user-activity .card-body {
124
- overflow: scroll;
145
+ overflow: auto;
125
146
  max-height: 20em;
126
147
  }
127
148