hyrax 5.2.0 → 5.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +111 -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
@@ -26,6 +26,9 @@ module Hyrax
26
26
  end
27
27
  end
28
28
 
29
+ include BasedNearFieldBehavior
30
+ # Remove until compound fields are merged
31
+ # include CompoundFieldBehavior
29
32
  class_attribute :model_class
30
33
 
31
34
  property :human_readable_type, writable: false
@@ -42,25 +45,87 @@ module Hyrax
42
45
  # @see https://github.com/samvera/valkyrie/wiki/Optimistic-Locking
43
46
  property :version, virtual: true, prepopulator: LockKeyPrepopulator
44
47
 
48
+ # Wire validators with `attributes:` through `validation { ... }` rather
49
+ # than the bare `validates_with`. Reform's `validates_with` shim closes
50
+ # over the args array, so the options hash (`{attributes: [:foo]}`) is
51
+ # shared across heritage replays. ActiveModel mutates that hash on each
52
+ # call (`options[:class] = self`, then `options.delete(:attributes)`
53
+ # inside `EachValidator#initialize`). The first replay leaves the hash
54
+ # without `:attributes`; the second replay raises
55
+ # `:attributes cannot be blank` and the subclass crashes at load time.
56
+ # Wrapping in `validation(name: :default, inherit: true) { ... }` rebuilds
57
+ # the literal options hash on every replay so each subclass gets its own
58
+ # clean copy. This pattern applies to *any* `validates_with` that takes
59
+ # an `attributes:` keyword.
60
+
45
61
  ##
46
62
  # @api public
47
63
  #
48
64
  # Forms should be initialized with an explicit +resource:+ parameter to
49
65
  # match indexers.
66
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
50
67
  def initialize(deprecated_resource = nil, resource: nil)
68
+ r = resource || deprecated_resource
69
+ if r.flexible?
70
+ self.class.deserializer_class = nil # need to reload this on first use after schema is loaded
71
+ singleton_class.schema_definitions = self.class.definitions
72
+ contexts = r.respond_to?(:contexts) ? r.contexts : nil
73
+ current_schema_fields = Hyrax::Schema.m3_schema_loader.form_definitions_for(schema: r.class.name, version: Hyrax::FlexibleSchema.current_schema_id, contexts: contexts)
74
+ current_schema_fields.each do |field_name, options|
75
+ singleton_class.property field_name.to_sym, options.merge(display: options.fetch(:display, true), default: [])
76
+ end
77
+ end
78
+
51
79
  if resource.nil?
52
80
  if !deprecated_resource.nil?
53
81
  Deprecation.warn "Initializing Valkyrie forms without an explicit resource parameter is deprecated. Pass the resource with `resource:` instead."
82
+ # Remove form definitions for attributes the model doesn't support,
83
+ # mirroring the cleanup in the resource: keyword path below.
84
+ if deprecated_resource.respond_to?(:flexible?) && deprecated_resource.flexible?
85
+ to_remove = singleton_class.definitions.select { |k, v| !deprecated_resource.respond_to?(k) && v.instance_variable_get("@options")[:display] }
86
+ to_remove.keys.each { |removed_field| singleton_class.definitions.delete(removed_field) }
87
+ end
54
88
  super(deprecated_resource)
55
89
  else
56
90
  super()
57
91
  end
58
92
  else
93
+ # make a new resource with all of the existing attributes
94
+ if resource.flexible?
95
+ hash = resource.attributes.dup
96
+ hash[:schema_version] = Hyrax::FlexibleSchema.current_schema_id
97
+ resource = resource.class.new(hash)
98
+ # find any fields removed by the current schema
99
+ current_field_keys = current_schema_fields.keys.map(&:to_s)
100
+ to_remove = singleton_class.definitions.select { |k, v| !current_field_keys.include?(k.to_s) && v.instance_variable_get("@options")[:display] }
101
+ to_remove.keys.each do |removed_field|
102
+ singleton_class.definitions.delete(removed_field)
103
+ end
104
+ end
105
+
59
106
  super(resource)
60
107
  end
61
108
  end
109
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
62
110
 
63
111
  class << self
112
+ def inherited(subclass)
113
+ # Field Behaviors must be prepended onto every subclass so their
114
+ # `deserialize!` overrides land above Reform's base method on the
115
+ # ancestor chain. Each behavior gates itself internally and is a
116
+ # no-op when its feature is off or its property isn't on the
117
+ # subclass's model.
118
+ subclass.prepend(BasedNearFieldBehavior)
119
+ subclass.prepend(RedirectsFieldBehavior)
120
+ super
121
+ end
122
+
123
+ def check_if_flexible(model)
124
+ return unless model.flexible?
125
+ include FlexibleFormBehavior
126
+ include Hyrax::FormFields(model.to_s, definition_loader: Hyrax::Schema.m3_schema_loader)
127
+ end
128
+
64
129
  ##
65
130
  # @api public
66
131
  #
@@ -69,11 +134,12 @@ module Hyrax
69
134
  # @example
70
135
  # monograph = Monograph.new
71
136
  # change_set = Hyrax::Forms::ResourceForm.for(resource: monograph)
72
- def for(deprecated_resource = nil, resource: nil)
137
+ def for(deprecated_resource = nil, resource: nil, admin_set_id: nil)
73
138
  if resource.nil? && !deprecated_resource.nil?
74
139
  Deprecation.warn "Initializing Valkyrie forms without an explicit resource parameter is deprecated. Pass the resource with `resource:` instead."
75
- return self.for(resource: deprecated_resource)
140
+ return self.for(resource: deprecated_resource, admin_set_id: admin_set_id)
76
141
  end
142
+ apply_admin_set_contexts(resource: resource, admin_set_id: admin_set_id)
77
143
  klass = "#{resource.class.name}Form".safe_constantize
78
144
  klass ||= Hyrax::Forms::ResourceForm(resource.class)
79
145
  begin
@@ -84,10 +150,23 @@ module Hyrax
84
150
  end
85
151
  end
86
152
 
153
+ private
154
+
155
+ def apply_admin_set_contexts(resource:, admin_set_id:)
156
+ return if admin_set_id.blank?
157
+ return unless resource.respond_to?(:flexible?) && resource.flexible?
158
+ admin_set = Hyrax.query_service.find_by(id: admin_set_id)
159
+ return unless admin_set&.respond_to?(:contexts)
160
+ contexts = Array(admin_set.contexts)
161
+ resource.contexts = contexts if contexts.present?
162
+ rescue Valkyrie::Persistence::ObjectNotFoundError
163
+ nil
164
+ end
165
+
87
166
  ##
88
167
  # @return [Array<Symbol>] list of required field names as symbols
89
168
  def required_fields
90
- definitions
169
+ schema_definitions
91
170
  .select { |_, definition| definition[:required] }
92
171
  .keys.map(&:to_sym)
93
172
  end
@@ -98,14 +177,27 @@ module Hyrax
98
177
  # @return [Array<Symbol>] list of required field names as symbols
99
178
  def required_fields=(fields)
100
179
  fields = fields.map(&:to_s)
101
- raise(KeyError) unless fields.all? { |f| definitions.key?(f) }
180
+ raise(KeyError) unless fields.all? { |f| schema_definitions.key?(f) }
102
181
 
103
- fields.each { |field| definitions[field].merge!(required: true) }
182
+ fields.each { |field| schema_definitions[field].merge!(required: true) }
104
183
 
105
184
  required_fields
106
185
  end
107
- end
108
186
 
187
+ def schema_definitions
188
+ @definitions
189
+ end
190
+
191
+ def schema_definitions=(values)
192
+ @definitions = values
193
+ end
194
+
195
+ def expose_class
196
+ @expose_class = Class.new(Disposable::Expose).from(schema_definitions.values)
197
+ end
198
+
199
+ public :expose_class, :required_fields, :required_fields=, :schema_definitions, :schema_definitions=
200
+ end
109
201
  ##
110
202
  # @param [#to_s] attr
111
203
  # @param [Object] value
@@ -127,9 +219,12 @@ module Hyrax
127
219
  # @return [Array<Symbol>] terms for display 'above-the-fold', or in the most
128
220
  # prominent form real estate
129
221
  def primary_terms
130
- _form_field_definitions
131
- .select { |_, definition| definition[:primary] }
132
- .keys.map(&:to_sym)
222
+ terms = _form_field_definitions
223
+ .select { |_, definition| definition[:primary] }
224
+ .keys.map(&:to_sym)
225
+
226
+ terms = [:schema_version, :contexts] + terms if model.flexible?
227
+ terms
133
228
  end
134
229
 
135
230
  ##
@@ -146,10 +241,16 @@ module Hyrax
146
241
  secondary_terms.any?
147
242
  end
148
243
 
244
+ delegate :flexible?, to: :model
245
+
149
246
  private
150
247
 
151
248
  def _form_field_definitions
152
- self.class.definitions
249
+ if model.flexible?
250
+ singleton_class.schema_definitions
251
+ else
252
+ self.class.definitions
253
+ end
153
254
  end
154
255
  end
155
256
  end
@@ -13,6 +13,7 @@ module Hyrax
13
13
  def self.PcdmObjectForm(work_class) # rubocop:disable Naming/MethodName
14
14
  Class.new(Hyrax::Forms::PcdmObjectForm) do
15
15
  self.model_class = work_class
16
+ include Hyrax::FormFields(:core_metadata) if work_class.ancestors.detect { |k| k.inspect == "Hyrax::Schema(core_metadata)" }
16
17
 
17
18
  ##
18
19
  # @return [String]
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyrax
4
+ module AttributesHelper
5
+ def view_options_for(presenter)
6
+ model_name = presenter.model.model_name.klass.to_s
7
+ if presenter.respond_to?(:flexible?) && presenter.flexible?
8
+ Hyrax::Schema.m3_schema_loader.view_definitions_for(schema: model_name, version: presenter.solr_document.schema_version, contexts: presenter.solr_document.contexts)
9
+ else
10
+ view_options_without_flexibility(presenter, model_name)
11
+ end
12
+ end
13
+
14
+ def view_options_without_flexibility(presenter, model_name)
15
+ model = presenter.model
16
+ schema = schema(model)
17
+
18
+ # no schema found for given model - try a few more fallbacks
19
+
20
+ # if wings is enabled we may be able to use the model registry to find the new model
21
+ if schema.nil? && !Hyrax.config.disable_wings
22
+ new_model = Wings::ModelRegistry.reverse_lookup(model)
23
+ schema = schema(new_model) if new_model
24
+ end
25
+ # Check if the model has a resource version
26
+ if schema.nil?
27
+ new_model = "#{model_name}Resource".safe_constantize
28
+ schema = schema(new_model) if new_model
29
+ end
30
+ # If we still don't have a schema, assume we have a pre-valkyrie model
31
+ if schema.nil?
32
+ if model.respond_to?(:local_attributes)
33
+ return model.local_attributes
34
+ else
35
+ return []
36
+ end
37
+ end
38
+
39
+ Hyrax::Schema.simple_schema_loader.view_definitions_for(schema:)
40
+ end
41
+
42
+ # @param [String] model's class name
43
+ # @return [Hash] the schema for the model or nil if not found
44
+ def schema(model)
45
+ return nil unless model.present?
46
+
47
+ # If this is an ActiveFedoraDummyModel, get the schema from the actual model class
48
+ if model.is_a?(Hyrax::ActiveFedoraDummyModel)
49
+ actual_model = model.instance_variable_get(:@model)
50
+ return schema(actual_model) if actual_model
51
+ end
52
+
53
+ # using respond_to? check because try? does not succeed with Dry::Types object that is returned by schema method
54
+ return nil unless model.respond_to?(:schema)
55
+ model.schema
56
+ end
57
+
58
+ # @param [String] field name
59
+ # @param [Hash<Hash>] a nested hash of view options...
60
+ # {:render_term=>:based_near_label, :label=>{"en"=>"Title", "es"=>"Título"}, :html_dl=>true}
61
+ # @return [String] the field name to be used for rendering
62
+ def conform_field(field_name, options_hash)
63
+ options_hash&.with_indifferent_access&.fetch('render_term', nil) || field_name
64
+ end
65
+
66
+ # @param [String] field name
67
+ # @param [Hash<Hash>] a nested hash of view options...
68
+ # {:label=>{"en"=>"Title", "es"=>"Título"}, :html_dl=>true}
69
+ # @return [Hash] the transformed options for the field
70
+ def conform_options(field_name, view_options)
71
+ hash_of_locales = view_options.delete(:display_label) || {}
72
+
73
+ if hash_of_locales.present?
74
+ view_options[:label] = hash_of_locales[locale] || hash_of_locales[:default]
75
+ else
76
+ view_options[:label] = (view_options[:render_term] || field_name).to_s
77
+ end
78
+ field = view_options[:label]
79
+ translate = I18n.t(field, default: field) if field.match(/\./)
80
+ if translate && translate != field
81
+ view_options[:label] = translate
82
+ else
83
+ view_options[:label] = field_label(
84
+ :"blacklight.search.fields.index.#{field}",
85
+ :"blacklight.search.fields.show.#{field}",
86
+ :"blacklight.search.fields.#{field}",
87
+ field.to_s.humanize
88
+ )
89
+ end
90
+ view_options[:base_url] = request.base_url if respond_to?(:request) && request.respond_to?(:base_url)
91
+ view_options
92
+ end
93
+
94
+ # Returns true when the field should render on the work show page.
95
+ # Honors these view options:
96
+ # * `show_page: false` — suppresses the field on the show page for everyone.
97
+ # * `admin_only: true` — only visible to admins.
98
+ # * `editor_only: true` — only visible to users the presenter reports as editors.
99
+ # Setting both `admin_only` and `editor_only` is effectively equivalent to
100
+ # `admin_only` alone: admins are editors of every record, so they pass both
101
+ # guards, but a plain editor of the record still fails the admin guard.
102
+ def field_visible?(view_options, presenter)
103
+ return false if view_options[:show_page] == false
104
+ return false if view_options[:admin_only] && !current_user&.admin?
105
+ return false if view_options[:editor_only] && !presenter.try(:editor?)
106
+ true
107
+ end
108
+ end
109
+ end
@@ -5,5 +5,31 @@ module Hyrax
5
5
  def application_name
6
6
  t('hyrax.product_name', default: super)
7
7
  end
8
+
9
+ # rubocop:disable Metrics/MethodLength
10
+ def index_field_label(document, field)
11
+ field_config = index_fields(document)[field]
12
+ return resolve_label(field_config) if field_config&.custom_label || field_config&.label&.respond_to?(:call)
13
+
14
+ translate = I18n.t(field_config.label, default: field_config.label) if field_config&.label&.match(/\./)
15
+ if translate && translate != field_config.label
16
+ field_label(translate, field_config.label, field.to_s.humanize)
17
+ else
18
+ field_label(
19
+ :"blacklight.search.fields.index.#{field}",
20
+ :"blacklight.search.fields.show.#{field}",
21
+ :"blacklight.search.fields.#{field}",
22
+ (field_config.label if field_config),
23
+ field.to_s.humanize
24
+ )
25
+ end
26
+ end
27
+ # rubocop:enable Metrics/MethodLength
28
+
29
+ private
30
+
31
+ def resolve_label(field_config)
32
+ field_config.label.respond_to?(:call) ? field_config.label.call : field_config.label
33
+ end
8
34
  end
9
35
  end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
  module Hyrax
3
3
  module CollectionsHelper # rubocop:disable Metrics/ModuleLength
4
+ include Hyrax::RedirectsTabHelper
5
+
4
6
  ##
5
7
  # @since 3.1.0
6
8
  # @return [Array<SolrDocument>]
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyrax
4
+ module FileSetFormHelper
5
+ def render_transcript_ids_field?(file_set)
6
+ return unless file_set.persisted?
7
+ return if @parent.nil?
8
+ case file_set
9
+ when ActiveFedora::Base
10
+ file_set.video? || file_set.audio?
11
+ when Valkyrie::Resource
12
+ service = Hyrax::FileSetTypeService.new(file_set: file_set)
13
+ service.video? || service.audio?
14
+ end
15
+ end
16
+
17
+ def transcript_ids_select_options
18
+ options = Forms::FileSetForm.available_transcripts(parent: @parent, current_ability: current_ability)
19
+ options.each_with_object({}) do |doc, hash|
20
+ hash[doc.title_or_label] = doc.id.to_s
21
+ end
22
+ end
23
+ end
24
+ end
@@ -19,6 +19,34 @@ module Hyrax
19
19
  include Hyrax::WorkFormHelper
20
20
  include Hyrax::WorkflowsHelper
21
21
  include Hyrax::FacetsHelper
22
+ include Hyrax::AttributesHelper
23
+ include Hyrax::PermalinkHelper
24
+ include Hyrax::WorksHelper
25
+ include Hyrax::FileSetFormHelper
26
+
27
+ ##
28
+ # @return [Array<String>] the list of admin sets available for creating works for this user
29
+ def available_admin_sets_for_creating_works(ability:)
30
+ return [] unless Flipflop.assign_admin_set?
31
+ return [] unless ability
32
+
33
+ source_ids = Hyrax::Collections::PermissionsService.source_ids_for_deposit(ability:, source_type: 'admin_set')
34
+
35
+ admin_sets_list = Hyrax.query_service.find_many_by_ids(ids: source_ids).map do |source|
36
+ [source.title.first, source.id]
37
+ end
38
+
39
+ # Sorts the default admin set to be first, then the rest by title.
40
+ admin_sets_list.sort do |a, b|
41
+ if Hyrax::AdminSetCreateService.default_admin_set?(id: a[1])
42
+ -1
43
+ elsif Hyrax::AdminSetCreateService.default_admin_set?(id: b[1])
44
+ 1
45
+ else
46
+ a[0] <=> b[0]
47
+ end
48
+ end
49
+ end
22
50
 
23
51
  ##
24
52
  # @return [Array<String>] the list of all user groups
@@ -233,7 +261,10 @@ module Hyrax
233
261
  # @return [ActiveSupport::SafeBuffer] license links, html_safe
234
262
  def license_links(options)
235
263
  service = Hyrax.config.license_service_class.new
236
- to_sentence(options[:value].map { |right| link_to service.label(right), right })
264
+ to_sentence(options[:value].map do |right|
265
+ label = service.label(right) { right }
266
+ Hyrax::AuthorityRenderingHelper.linkable_uri?(right) ? link_to(label, right) : ERB::Util.h(label)
267
+ end)
237
268
  end
238
269
 
239
270
  # A Blacklight index field helper_method
@@ -241,7 +272,10 @@ module Hyrax
241
272
  # @return [ActiveSupport::SafeBuffer] rights statement links, html_safe
242
273
  def rights_statement_links(options)
243
274
  service = Hyrax.config.rights_statement_service_class.new
244
- to_sentence(options[:value].map { |right| link_to service.label(right), right })
275
+ to_sentence(options[:value].map do |right|
276
+ label = service.label(right) { right }
277
+ Hyrax::AuthorityRenderingHelper.linkable_uri?(right) ? link_to(label, right) : ERB::Util.h(label)
278
+ end)
245
279
  end
246
280
 
247
281
  # A Blacklight facet field helper_method
@@ -288,6 +322,21 @@ module Hyrax
288
322
  tag.span("", class: [Hyrax::ModelIcon.css_class_for(::Collection), "collection-icon-search"])
289
323
  end
290
324
 
325
+ # Returns alt text for a thumbnail image.
326
+ # When the document has a custom thumbnail (thumbnail_alt_text indexed), delegates to
327
+ # alt_text_for_view to get the specific alt text. Otherwise returns a generic fallback
328
+ # (hyrax.sr.thumbnail) indicating a default representative image is shown.
329
+ # Apps can override this method to inject content-block lookups or other custom logic.
330
+ #
331
+ # @param document [SolrDocument]
332
+ # @param block_name [String] unused here; provided for API compatibility with overrides
333
+ # @return [String]
334
+ def thumbnail_alt_text_for(document, block_name: nil) # rubocop:disable Lint/UnusedMethodArgument
335
+ return document.alt_text_for_view if document.respond_to?(:thumbnail_alt_text) && document.thumbnail_alt_text.present?
336
+
337
+ t('hyrax.sr.thumbnail')
338
+ end
339
+
291
340
  def collection_title_by_id(id)
292
341
  solr_docs = controller.blacklight_config.repository.find(id).docs
293
342
  return nil if solr_docs.empty?
@@ -10,8 +10,18 @@ module Hyrax
10
10
  'hyrax/base/iiif_viewers/' + work_presenter.iiif_viewer.to_s
11
11
  end
12
12
 
13
+ # For backwards compatibility
13
14
  def universal_viewer_base_url
14
- "#{request&.base_url}/uv/uv.html"
15
+ iiif_viewer_base_url(:universal_viewer)
16
+ end
17
+
18
+ def iiif_viewer_base_url(viewer)
19
+ case viewer
20
+ when :universal_viewer
21
+ "#{request&.base_url}/uv/uv.html"
22
+ else
23
+ "#{request&.base_url}/#{viewer}/#{viewer}.html"
24
+ end
15
25
  end
16
26
 
17
27
  def universal_viewer_config_url
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyrax
4
+ # Helpers for the "Copy permalink" button on work and collection show pages.
5
+ # See documentation/copy_permalink.md.
6
+ module PermalinkHelper
7
+ # The UUID-based URL for the record represented by `presenter`, so
8
+ # it is stable across alias changes and is safe to share or cite.
9
+ def permalink_for(presenter)
10
+ strip_query_string(request.base_url + Hyrax::PermalinkPath.call(presenter))
11
+ end
12
+
13
+ # The URL used in the show page's `<link rel="canonical">` tag.
14
+ def canonical_url_for(presenter)
15
+ display_path = Hyrax.config.redirects_active? && Hyrax::RedirectsLookup.display_path_for(presenter.id.to_s)
16
+ return permalink_for(presenter) if display_path.blank?
17
+ strip_query_string(request.base_url + display_path)
18
+ end
19
+
20
+ def copy_permalink_enabled?
21
+ Flipflop.enabled?(:copy_permalink_button)
22
+ end
23
+
24
+ private
25
+
26
+ # Removes the `?…` query string from a URL so the permalink is a clean
27
+ # canonical reference. Rails URL helpers append `?locale=...` (and any
28
+ # other registered `default_url_options`) by default; for a stable
29
+ # citable URL we want the bare host + path.
30
+ def strip_query_string(url)
31
+ parsed = URI.parse(url)
32
+ parsed.query = nil
33
+ parsed.fragment = nil
34
+ parsed.to_s
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyrax
4
+ ##
5
+ # Decides whether the Aliases tab should appear on a work or
6
+ # collection edit form. Included into `WorkFormHelper` and
7
+ # `CollectionsHelper` so both forms share one rule.
8
+ #
9
+ # The tab appears only when the redirects feature is fully active
10
+ # (`Hyrax.config.redirects_active?`), the form is a ResourceForm
11
+ # (the only form pipeline with the redirects populator, validator,
12
+ # and prepopulator wired in), AND the form's underlying resource
13
+ # carries the `redirects` attribute. The structural check guards
14
+ # against adopter work or collection classes that don't include
15
+ # the redirects schema; without it the tab would render and crash
16
+ # on `f.object.redirects`.
17
+ module RedirectsTabHelper
18
+ def redirects_tab?(form)
19
+ return false unless Hyrax.config.redirects_active?
20
+ return false unless redirects_supported_form?(form)
21
+ target = form.respond_to?(:model) ? form.model : form
22
+ target.respond_to?(:redirects)
23
+ end
24
+
25
+ def redirects_supported_form?(form)
26
+ form.is_a?(Hyrax::Forms::ResourceForm)
27
+ end
28
+ end
29
+ end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
  module Hyrax
3
3
  module WorkFormHelper
4
+ include Hyrax::RedirectsTabHelper
5
+
4
6
  ##
5
7
  # @todo this implementation hits database backends (solr) and is invoked
6
8
  # from views. refactor to avoid
@@ -30,11 +32,13 @@ module Hyrax
30
32
  # @param form [Hyrax::Forms::WorkForm, Hyrax::Forms::ResourceForm]
31
33
  # @return [Array<String>] the list of names of tabs to be rendered in the form
32
34
  def form_tabs_for(form:)
33
- if form.instance_of? Hyrax::Forms::BatchUploadForm
34
- %w[files metadata relationships]
35
- else
36
- %w[metadata files relationships]
37
- end
35
+ tabs = if form.instance_of? Hyrax::Forms::BatchUploadForm
36
+ %w[files metadata relationships]
37
+ else
38
+ %w[metadata files relationships]
39
+ end
40
+ tabs << 'redirects' if redirects_tab?(form)
41
+ tabs
38
42
  end
39
43
 
40
44
  ##
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyrax
4
+ module WorksHelper
5
+ def available_collections(work:)
6
+ return [] if @current_ability.blank?
7
+
8
+ all_collections = Hyrax::CollectionsService.new(self).all_search_results(:deposit)
9
+ return all_collections if work.blank?
10
+
11
+ all_collections.reject { |col| work.member_of_collection_ids.include?(col.id) }
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyrax
4
+ module WorkflowIndexer
5
+ # Write the workflow roles and state into the solr_document
6
+ # @param [Hash] solr_document the solr document to add the fields to
7
+ def to_solr
8
+ super.tap do |solr_doc|
9
+ index_workflow_fields(solr_doc)
10
+ end
11
+ end
12
+
13
+ # Write the workflow roles and state so one can see where the document moves to next
14
+ # @param [Hash] solr_document the solr document to add the field to
15
+ def index_workflow_fields(solr_document)
16
+ entity = Sipity::Entity(resource)
17
+ solr_document['actionable_workflow_roles_ssim'] = workflow_roles(entity).map { |role| "#{entity.workflow.permission_template.source_id}-#{entity.workflow.name}-#{role}" }
18
+ solr_document['workflow_state_name_ssim'] = entity.workflow_state.name if entity.workflow_state
19
+ rescue Sipity::ConversionError
20
+ nil
21
+ end
22
+
23
+ # Get the workflow roles for the entity
24
+ # @param [Sipity::Entity] entity the entity to get the workflow roles for
25
+ # @return [Array<String>] the workflow roles for the entity
26
+ def workflow_roles(entity)
27
+ Hyrax::Workflow::PermissionQuery.scope_roles_associated_with_the_given_entity(entity: entity)
28
+ end
29
+ end
30
+ end
@@ -9,6 +9,7 @@ module Hyrax
9
9
  super.tap do |solr_doc|
10
10
  solr_doc['hasRelatedMediaFragment_ssim'] = object.representative_id
11
11
  solr_doc['hasRelatedImage_ssim'] = object.thumbnail_id
12
+ solr_doc['transcript_ids_ssim'] = object.transcript_ids
12
13
  # Label is the actual file name. It's not editable by the user.
13
14
  solr_doc['label_tesim'] = object.label
14
15
  solr_doc['label_ssi'] = object.label
@@ -7,7 +7,8 @@ module Hyrax
7
7
  class AdministrativeSetIndexer < Hyrax::Indexers::ResourceIndexer
8
8
  include Hyrax::PermissionIndexer
9
9
  include Hyrax::VisibilityIndexer
10
- include Hyrax::Indexer(:core_metadata)
10
+ include Hyrax::Indexer(:core_metadata) if Hyrax.config.admin_set_include_metadata
11
+ check_if_flexible(Hyrax::AdministrativeSet)
11
12
 
12
13
  def to_solr # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
13
14
  super.tap do |solr_doc|
@@ -8,8 +8,11 @@ module Hyrax
8
8
  include Hyrax::PermissionIndexer
9
9
  include Hyrax::VisibilityIndexer
10
10
  include Hyrax::ThumbnailIndexer
11
- include Hyrax::Indexer(:core_metadata)
12
- include Hyrax::Indexer(:file_set_metadata)
11
+ if Hyrax.config.file_set_include_metadata
12
+ include Hyrax::Indexer(:core_metadata)
13
+ include Hyrax::Indexer(:file_set_metadata)
14
+ end
15
+ check_if_flexible(Hyrax::FileSet)
13
16
 
14
17
  def to_solr # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
15
18
  super.tap do |solr_doc| # rubocop:disable Metrics/BlockLength
@@ -21,6 +24,7 @@ module Hyrax
21
24
  solr_doc['extracted_text_id_ssi'] = resource.extracted_text_id.to_s
22
25
  solr_doc['hasRelatedMediaFragment_ssim'] = resource.representative_id.to_s
23
26
  solr_doc['hasRelatedImage_ssim'] = resource.thumbnail_id.to_s
27
+ solr_doc['transcript_ids_ssim'] = resource.transcript_ids&.map(&:to_s) if resource.respond_to?(:transcript_ids)
24
28
 
25
29
  index_lease(solr_doc)
26
30
  index_embargo(solr_doc)