hyrax 5.0.1 → 5.0.3

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 (247) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +7 -176
  3. data/.dassie/.env +8 -3
  4. data/.dassie/Gemfile +13 -2
  5. data/.dassie/app/controllers/hyrax/generic_work_resources_controller.rb +17 -0
  6. data/.dassie/app/controllers/hyrax/generic_works_controller.rb +7 -1
  7. data/.dassie/app/forms/generic_work_resource_form.rb +20 -0
  8. data/.dassie/app/indexers/generic_work_resource_indexer.rb +16 -0
  9. data/.dassie/app/models/admin_set_resource.rb +9 -0
  10. data/.dassie/app/models/collection_resource.rb +2 -0
  11. data/.dassie/app/models/file_set.rb +2 -0
  12. data/.dassie/app/models/generic_work_resource.rb +10 -0
  13. data/.dassie/app/views/hyrax/generic_work_resources/_generic_work_resource.html.erb +2 -0
  14. data/.dassie/config/analytics.yml +6 -1
  15. data/.dassie/config/application.rb +24 -0
  16. data/.dassie/config/initializers/hyrax.rb +13 -3
  17. data/.dassie/config/initializers/wings.rb +109 -0
  18. data/.dassie/config/metadata/generic_work_resource.yaml +22 -0
  19. data/.dassie/config/valkyrie_index.yml +4 -10
  20. data/.dassie/db/migrate/20240506070809_valkyrie_id_to_string.rb +5 -0
  21. data/.dassie/db/schema.rb +2 -2
  22. data/.dassie/spec/indexers/generic_work_resource_indexer_spec.rb +13 -0
  23. data/.dassie/spec/models/generic_work_resource_spec.rb +12 -0
  24. data/.dassie/spec/views/generic_work_resources/_generic_work_resource.html.erb_spec.rb +7 -0
  25. data/.dockerignore +6 -4
  26. data/.github/release.yml +3 -0
  27. data/.github/workflows/lint-build-test.yml +130 -0
  28. data/.github/workflows/test-results.yml +40 -0
  29. data/.koppie/.env +7 -5
  30. data/.koppie/Gemfile +12 -1
  31. data/.koppie/config/analytics.yml +6 -1
  32. data/.koppie/config/environments/test.rb +2 -0
  33. data/.koppie/config/initializers/1_valkyrie.rb +6 -2
  34. data/.koppie/config/solr.yml +1 -1
  35. data/.regen +1 -1
  36. data/.rubocop.yml +5 -0
  37. data/Dockerfile +16 -36
  38. data/Gemfile +2 -0
  39. data/app/assets/javascripts/hydra-editor/field_manager.es6 +187 -0
  40. data/app/assets/javascripts/hyrax/analytics_events.js +48 -24
  41. data/app/assets/javascripts/hyrax/collapse.js +4 -4
  42. data/app/assets/javascripts/hyrax/file_manager/save_manager.es6 +2 -0
  43. data/app/assets/javascripts/hyrax/search.js +2 -3
  44. data/app/assets/javascripts/hyrax/select_work_type.es6 +3 -1
  45. data/app/assets/javascripts/hyrax/uploader.js +20 -18
  46. data/app/assets/javascripts/hyrax.js +1 -0
  47. data/app/assets/stylesheets/_bootstrap-default-overrides.scss +4 -0
  48. data/app/assets/stylesheets/hyrax/_card.scss +4 -0
  49. data/app/assets/stylesheets/hyrax/_catalog.scss +21 -0
  50. data/app/assets/stylesheets/hyrax/_collections.scss +1 -1
  51. data/app/assets/stylesheets/hyrax/_facets.scss +15 -3
  52. data/app/assets/stylesheets/hyrax/_featured.scss +4 -0
  53. data/app/assets/stylesheets/hyrax/_form.scss +4 -0
  54. data/app/assets/stylesheets/hyrax/_forms.scss +2 -1
  55. data/app/assets/stylesheets/hyrax/_nestable.scss +9 -8
  56. data/app/assets/stylesheets/hyrax/_select_work_type.scss +12 -0
  57. data/app/assets/stylesheets/hyrax/_styles.scss +4 -0
  58. data/app/assets/stylesheets/hyrax/_work-show.scss +3 -0
  59. data/app/controllers/concerns/hyrax/singular_subresource_controller.rb +7 -2
  60. data/app/controllers/concerns/hyrax/valkyrie_downloads_controller_behavior.rb +11 -2
  61. data/app/controllers/concerns/hyrax/works_controller_behavior.rb +9 -2
  62. data/app/controllers/hyrax/admin/analytics/collection_reports_controller.rb +2 -2
  63. data/app/controllers/hyrax/admin/analytics/work_reports_controller.rb +7 -8
  64. data/app/controllers/hyrax/dashboard/collections_controller.rb +2 -1
  65. data/app/controllers/hyrax/downloads_controller.rb +24 -3
  66. data/app/controllers/hyrax/file_sets_controller.rb +32 -6
  67. data/app/controllers/hyrax/my/works_controller.rb +20 -0
  68. data/app/controllers/hyrax/stats_controller.rb +1 -1
  69. data/app/controllers/hyrax/uploads_controller.rb +28 -2
  70. data/app/forms/hyrax/forms/admin/appearance.rb +1 -1
  71. data/app/forms/hyrax/forms/admin/collection_type_form.rb +1 -7
  72. data/app/forms/hyrax/forms/pcdm_collection_form.rb +9 -0
  73. data/app/forms/hyrax/forms/work_embargo_form.rb +6 -0
  74. data/app/forms/hyrax/forms/work_lease_form.rb +6 -0
  75. data/app/indexers/concerns/hyrax/location_indexer.rb +2 -2
  76. data/app/indexers/hyrax/indexers/file_set_indexer.rb +4 -0
  77. data/app/indexers/hyrax/indexers/resource_indexer.rb +1 -0
  78. data/app/indexers/hyrax/valkyrie_indexer.rb +3 -5
  79. data/app/jobs/migrate_files_to_valkyrie_job.rb +109 -0
  80. data/app/jobs/migrate_resources_job.rb +34 -0
  81. data/app/jobs/valkyrie_create_derivatives_job.rb +2 -1
  82. data/app/models/admin_set.rb +1 -0
  83. data/app/models/concerns/hyrax/ar_resource.rb +104 -0
  84. data/app/models/concerns/hyrax/solr_document/ordered_members.rb +2 -1
  85. data/app/models/concerns/hyrax/solr_document_behavior.rb +13 -2
  86. data/app/models/concerns/hyrax/valkyrie_lazy_migration.rb +82 -0
  87. data/app/models/file_download_stat.rb +1 -1
  88. data/app/models/file_view_stat.rb +1 -1
  89. data/app/models/hyrax/collection_type.rb +12 -4
  90. data/app/models/hyrax/file_metadata.rb +19 -0
  91. data/app/models/hyrax/file_set.rb +25 -0
  92. data/app/models/hyrax/model_registry.rb +2 -3
  93. data/app/models/hyrax/resource.rb +5 -0
  94. data/app/models/hyrax/statistic.rb +12 -37
  95. data/app/presenters/hyrax/file_set_presenter.rb +2 -1
  96. data/app/presenters/hyrax/file_usage.rb +3 -3
  97. data/app/presenters/hyrax/iiif_manifest_presenter.rb +2 -1
  98. data/app/presenters/hyrax/member_presenter_factory.rb +7 -1
  99. data/app/presenters/hyrax/menu_presenter.rb +1 -1
  100. data/app/presenters/hyrax/stats_usage_presenter.rb +2 -1
  101. data/app/presenters/hyrax/work_show_presenter.rb +13 -17
  102. data/app/presenters/hyrax/work_usage.rb +5 -2
  103. data/app/search_builders/hyrax/expired_embargo_search_builder.rb +7 -1
  104. data/app/search_builders/hyrax/expired_lease_search_builder.rb +7 -1
  105. data/app/search_builders/hyrax/filter_by_type.rb +1 -3
  106. data/app/search_builders/hyrax/valkyrie_abstract_type_relation.rb +7 -2
  107. data/app/services/hyrax/access_control_list.rb +1 -1
  108. data/app/services/hyrax/admin_set_create_service.rb +16 -5
  109. data/app/services/hyrax/admin_set_service.rb +2 -1
  110. data/app/services/hyrax/analytics/ga4/base.rb +96 -0
  111. data/app/services/hyrax/analytics/ga4/events.rb +25 -0
  112. data/app/services/hyrax/analytics/ga4/events_daily.rb +36 -0
  113. data/app/services/hyrax/analytics/ga4/visits.rb +33 -0
  114. data/app/services/hyrax/analytics/ga4/visits_daily.rb +24 -0
  115. data/app/services/hyrax/analytics/ga4.rb +204 -0
  116. data/app/services/hyrax/analytics/google.rb +16 -2
  117. data/app/services/hyrax/analytics/matomo.rb +16 -3
  118. data/app/services/hyrax/analytics/results.rb +6 -0
  119. data/app/services/hyrax/custom_queries/find_access_control.rb +1 -1
  120. data/app/services/hyrax/custom_queries/find_by_date_range.rb +6 -23
  121. data/app/services/hyrax/custom_queries/find_collections_by_type.rb +2 -2
  122. data/app/services/hyrax/custom_queries/find_count_by.rb +3 -31
  123. data/app/services/hyrax/custom_queries/find_file_metadata.rb +2 -2
  124. data/app/services/hyrax/custom_queries/find_models_by_access.rb +5 -27
  125. data/app/services/hyrax/embargo_manager.rb +2 -1
  126. data/app/services/hyrax/listeners/file_listener.rb +2 -2
  127. data/app/services/hyrax/lock_manager.rb +6 -6
  128. data/app/services/hyrax/lockable.rb +4 -3
  129. data/app/services/hyrax/simple_schema_loader.rb +1 -1
  130. data/app/services/hyrax/solr_service.rb +22 -8
  131. data/app/services/hyrax/statistics/query_service.rb +1 -1
  132. data/app/services/hyrax/statistics/works/over_time.rb +1 -1
  133. data/app/services/hyrax/thumbnail_path_service.rb +2 -0
  134. data/app/services/hyrax/user_stat_importer.rb +5 -5
  135. data/app/services/hyrax/valkyrie_upload.rb +9 -7
  136. data/app/services/hyrax/versioning_service.rb +10 -2
  137. data/app/services/hyrax/work_query_service.rb +2 -2
  138. data/app/services/migrate_resource_service.rb +55 -0
  139. data/app/views/_controls.html.erb +5 -5
  140. data/app/views/_masthead.html.erb +1 -1
  141. data/app/views/catalog/_search_form.html.erb +9 -16
  142. data/app/views/catalog/_thumbnail_list_collection.html.erb +1 -1
  143. data/app/views/catalog/_thumbnail_list_default.html.erb +2 -2
  144. data/app/views/hyrax/admin/analytics/collection_reports/index.html.erb +4 -4
  145. data/app/views/hyrax/admin/analytics/work_reports/index.html.erb +1 -1
  146. data/app/views/hyrax/admin/collection_types/_form.html.erb +4 -4
  147. data/app/views/hyrax/admin/collection_types/index.html.erb +1 -1
  148. data/app/views/hyrax/admin/features/index.html.erb +1 -1
  149. data/app/views/hyrax/base/_file_manager_actions.html.erb +1 -1
  150. data/app/views/hyrax/base/_file_manager_member.html.erb +7 -4
  151. data/app/views/hyrax/base/_file_manager_thumbnail.html.erb +1 -1
  152. data/app/views/hyrax/base/_form_files.html.erb +1 -1
  153. data/app/views/hyrax/base/_form_member_of_collections.html.erb +4 -0
  154. data/app/views/hyrax/base/_show_actions.html.erb +7 -8
  155. data/app/views/hyrax/base/_work_button_row.html.erb +1 -1
  156. data/app/views/hyrax/batch_select/_add_button.html.erb +1 -1
  157. data/app/views/hyrax/content_blocks/_form.html.erb +3 -3
  158. data/app/views/hyrax/dashboard/_sidebar.html.erb +1 -1
  159. data/app/views/hyrax/dashboard/_user_activity.html.erb +2 -2
  160. data/app/views/hyrax/dashboard/collections/_form.html.erb +4 -4
  161. data/app/views/hyrax/dashboard/collections/_form_share.html.erb +6 -4
  162. data/app/views/hyrax/dashboard/collections/_list_collections.html.erb +1 -1
  163. data/app/views/hyrax/dashboard/collections/_show_document_list_row.html.erb +1 -1
  164. data/app/views/hyrax/dashboard/show_admin.html.erb +18 -19
  165. data/app/views/hyrax/dashboard/sidebar/_activity.html.erb +1 -1
  166. data/app/views/hyrax/embargoes/_list_expired_active_embargoes.html.erb +7 -7
  167. data/app/views/hyrax/file_sets/_actions.html.erb +9 -1
  168. data/app/views/hyrax/file_sets/_permission_form.html.erb +4 -2
  169. data/app/views/hyrax/file_sets/_show_actions.html.erb +1 -1
  170. data/app/views/hyrax/homepage/_featured.html.erb +1 -1
  171. data/app/views/hyrax/homepage/_recent_document.html.erb +2 -2
  172. data/app/views/hyrax/leases/_list_expired_active_leases.html.erb +6 -6
  173. data/app/views/hyrax/my/collections/_list_collections.html.erb +1 -1
  174. data/app/views/hyrax/my/collections/_tabs.html.erb +1 -1
  175. data/app/views/hyrax/pages/_form.html.erb +8 -8
  176. data/app/views/hyrax/transfers/_received.html.erb +1 -1
  177. data/app/views/hyrax/uploads/create.json.jbuilder +2 -2
  178. data/app/views/hyrax/users/_activity_log.html.erb +15 -9
  179. data/app/views/hyrax/users/_user_row.html.erb +6 -3
  180. data/app/views/hyrax/users/_vitals.html.erb +3 -2
  181. data/app/views/layouts/_head_tag_content.html.erb +2 -0
  182. data/app/views/shared/_appearance_styles.html.erb +5 -1
  183. data/app/views/shared/_ga4.html.erb +11 -0
  184. data/app/views/shared/_select_work_type_modal.html.erb +10 -1
  185. data/bin/db-migrate-seed.sh +3 -3
  186. data/bin/dev-entrypoint.sh +7 -2
  187. data/bin/{db-wait.sh → service-wait.sh} +1 -1
  188. data/bin/worker-entrypoint.sh +8 -0
  189. data/chart/hyrax/templates/deployment-worker.yaml +2 -2
  190. data/config/locales/hyrax.en.yml +4 -2
  191. data/config/metadata/basic_metadata.yaml +20 -0
  192. data/config/metadata/hyrax_internal_metadata.yaml +1 -1
  193. data/docker-compose-dassie.yml +167 -0
  194. data/docker-compose-koppie.yml +21 -36
  195. data/docker-compose-sirenia.yml +50 -44
  196. data/docker-compose.yml +2 -183
  197. data/documentation/developing-your-hyrax-based-app.md +2 -2
  198. data/hyrax.gemspec +5 -4
  199. data/lib/freyja/custom_query_container.rb +5 -0
  200. data/lib/freyja/metadata_adapter.rb +32 -0
  201. data/lib/freyja/persister.rb +42 -0
  202. data/lib/freyja/query_service.rb +20 -0
  203. data/lib/freyja/resource_factory.rb +8 -0
  204. data/lib/freyja.rb +14 -0
  205. data/lib/frigg/custom_query_container.rb +5 -0
  206. data/lib/frigg/metadata_adapter.rb +22 -0
  207. data/lib/frigg/persister.rb +33 -0
  208. data/lib/frigg/query_service.rb +15 -0
  209. data/lib/frigg.rb +13 -0
  210. data/lib/generators/hyrax/install_generator.rb +5 -0
  211. data/lib/generators/hyrax/templates/config/analytics.yml +6 -1
  212. data/lib/generators/hyrax/templates/config/initializers/1_valkyrie.rb +6 -2
  213. data/lib/generators/hyrax/templates/config/valkyrie_index.yml +1 -1
  214. data/lib/goddess/custom_query_container.rb +71 -0
  215. data/lib/goddess/metadata.rb +13 -0
  216. data/lib/goddess/query.rb +176 -0
  217. data/lib/hyrax/configuration.rb +83 -0
  218. data/lib/hyrax/engine.rb +2 -0
  219. data/lib/hyrax/form_fields.rb +1 -3
  220. data/lib/hyrax/name.rb +5 -0
  221. data/lib/hyrax/rubocop/custom_cops.rb +30 -0
  222. data/lib/hyrax/specs/capybara.rb +10 -6
  223. data/lib/hyrax/specs/shared_specs/factories/admin_sets.rb +2 -0
  224. data/lib/hyrax/specs/shared_specs/factories/hyrax_embargo.rb +4 -0
  225. data/lib/hyrax/specs/shared_specs/factories/hyrax_lease.rb +4 -0
  226. data/lib/hyrax/specs/shared_specs/factories/hyrax_work.rb +16 -2
  227. data/lib/hyrax/specs/shared_specs/hydra_works.rb +1 -1
  228. data/lib/hyrax/transactions/admin_set_destroy.rb +2 -1
  229. data/lib/hyrax/transactions/collection_destroy.rb +2 -1
  230. data/lib/hyrax/transactions/container.rb +9 -0
  231. data/lib/hyrax/transactions/steps/add_file_sets.rb +2 -1
  232. data/lib/hyrax/transactions/steps/delete_permission_template.rb +30 -0
  233. data/lib/hyrax/transactions/steps/delete_resource.rb +1 -1
  234. data/lib/hyrax/transactions/steps/save_collection_logo.rb +2 -1
  235. data/lib/hyrax/valkyrie_can_can_adapter.rb +8 -1
  236. data/lib/hyrax/version.rb +1 -1
  237. data/lib/wings/active_fedora_converter.rb +13 -5
  238. data/lib/wings/converter_value_mapper.rb +1 -0
  239. data/lib/wings/services/custom_queries/find_collections_by_type.rb +2 -1
  240. data/lib/wings/services/custom_queries/find_file_metadata.rb +2 -2
  241. data/lib/wings/setup.rb +12 -3
  242. data/lib/wings/transformer_value_mapper.rb +5 -1
  243. data/lib/wings/valkyrie/persister.rb +3 -1
  244. data/template.rb +1 -1
  245. metadata +77 -19
  246. data/.koppie/scripts/db-migrate-seed.sh +0 -9
  247. data/.koppie/scripts/entrypoint.sh +0 -10
@@ -140,8 +140,9 @@ module Hyrax
140
140
  # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
141
141
  def create_or_update_embargo_on_members(members, work)
142
142
  # TODO: account for all members and levels, not just file sets. ref: #6131
143
-
144
143
  members.each do |member|
144
+ # reload member to make sure nothing in the transaction has changed it already
145
+ member = Hyrax.query_service.find_by(id: member.id)
145
146
  member_embargo_needs_updating = work.embargo.updated_at > member.embargo&.updated_at if member.embargo
146
147
 
147
148
  if member.embargo && member_embargo_needs_updating
@@ -29,8 +29,8 @@ module Hyrax
29
29
  # @param [Dry::Events::Event] event
30
30
  # @return [void]
31
31
  def on_file_uploaded(event)
32
- # Run characterization for original file only
33
- return unless event[:metadata]&.original_file?
32
+ # Run characterization for original file only and allow optional skip paramater
33
+ return if event.payload[:skip_derivatives] || !event[:metadata]&.original_file?
34
34
 
35
35
  ValkyrieCharacterizationJob.perform_later(event[:metadata].id.to_s)
36
36
  end
@@ -16,11 +16,11 @@ module Hyrax
16
16
 
17
17
  ##
18
18
  # Blocks until lock is acquired or timeout.
19
- def lock(key)
19
+ def lock(key, ttl: @ttl, retry_count: @retry_count, retry_delay: @retry_delay)
20
20
  returned_from_block = nil
21
21
 
22
22
  pool.then do |conn|
23
- client(conn).lock(key, @ttl) do |locked|
23
+ client(conn, retry_count: retry_count, retry_delay: retry_delay).lock(key, ttl) do |locked|
24
24
  raise UnableToAcquireLockError unless locked
25
25
  returned_from_block = yield
26
26
  end
@@ -31,16 +31,16 @@ module Hyrax
31
31
  Hyrax.logger.error(err.message)
32
32
  raise(ConnectionPool::TimeoutError,
33
33
  "Failed to acquire a lock from Redlock due to a Redis connection " \
34
- "timeout: #{err}. If you are using Redis via `ConnectionPool` " \
35
- "you may wish to increase the pool size.")
34
+ "timeout: #{err}. If you are using Redis via `ConnectionPool` " \
35
+ "you may wish to increase the pool size.")
36
36
  end
37
37
 
38
38
  private
39
39
 
40
40
  ##
41
41
  # @api_private
42
- def client(conn)
43
- Redlock::Client.new([conn], retry_count: @retry_count, retry_delay: @retry_delay)
42
+ def client(conn, retry_count:, retry_delay:)
43
+ Redlock::Client.new([conn], retry_count: retry_count, retry_delay: retry_delay)
44
44
  end
45
45
 
46
46
  ##
@@ -1,11 +1,12 @@
1
1
  # frozen_string_literal: true
2
+ require 'forwardable'
3
+
2
4
  module Hyrax
3
5
  module Lockable
6
+ extend Forwardable
4
7
  extend ActiveSupport::Concern
5
8
 
6
- def acquire_lock_for(lock_key, &block)
7
- lock_manager.lock(lock_key, &block)
8
- end
9
+ def_delegator :lock_manager, :lock, :acquire_lock_for
9
10
 
10
11
  def lock_manager
11
12
  @lock_manager ||= LockManager.new(
@@ -158,7 +158,7 @@ module Hyrax
158
158
  end
159
159
 
160
160
  def config_search_paths
161
- [Rails.root, Hyrax::Engine.root]
161
+ Hyrax.config.simple_schema_loader_config_search_paths
162
162
  end
163
163
 
164
164
  def metadata_files
@@ -54,7 +54,7 @@ module Hyrax
54
54
  end
55
55
 
56
56
  delegate :add, :commit, :count, :delete, :get, :instance, :ping, :post,
57
- :query, :query_result, :delete_by_query, :search_by_id, :wipe!, to: :new
57
+ :query, :query_result, :query_in_batches, :delete_by_query, :search_by_id, :wipe!, to: :new
58
58
  end
59
59
 
60
60
  # Wraps rsolr get
@@ -111,6 +111,20 @@ module Hyrax
111
111
  end
112
112
  end
113
113
 
114
+ def query_in_batches(query, **args)
115
+ args[:rows] ||= 500
116
+ args[:start] ||= 0
117
+ loop do
118
+ result = query_result(query, **args)
119
+ break if result['response']['docs'].blank? || result['response']['numFound'] <= args[:start]
120
+ result['response']['docs'].select do |doc|
121
+ yield ::SolrHit.new(doc)
122
+ nil
123
+ end
124
+ args[:start] += args[:rows]
125
+ end
126
+ end
127
+
114
128
  # Wraps rsolr :delete_by_query
115
129
  def delete_by_query(query, **args)
116
130
  connection.delete_by_query(query, params: args)
@@ -149,6 +163,13 @@ module Hyrax
149
163
  result.first
150
164
  end
151
165
 
166
+ ##
167
+ # @api private
168
+ def connection
169
+ return self.class.instance.conn unless use_valkyrie
170
+ valkyrie_index.connection
171
+ end
172
+
152
173
  private
153
174
 
154
175
  ##
@@ -163,13 +184,6 @@ module Hyrax
163
184
  Hyrax.index_adapter
164
185
  end
165
186
 
166
- ##
167
- # @api private
168
- def connection
169
- return self.class.instance.conn unless use_valkyrie
170
- valkyrie_index.connection
171
- end
172
-
173
187
  def rows_warning
174
188
  "Calling Hyrax::SolrService.get without passing an explicit value for ':rows' is not recommended. You will end up with Solr's default (usually set to 10)\nCalled by #{caller[0]}"
175
189
  end
@@ -45,7 +45,7 @@ module Hyrax
45
45
  delegate :count, to: :relation
46
46
 
47
47
  def relation
48
- Hyrax::WorkRelation.new
48
+ Hyrax.config.disable_wings ? Hyrax::ValkyrieWorkRelation.new : Hyrax::WorkRelation.new
49
49
  end
50
50
 
51
51
  private
@@ -16,7 +16,7 @@ module Hyrax
16
16
  private
17
17
 
18
18
  def relation
19
- Hyrax::WorkRelation.new
19
+ Hyrax.config.disable_wings ? Hyrax::ValkyrieWorkRelation.new : Hyrax::WorkRelation.new
20
20
  end
21
21
  end
22
22
  end
@@ -31,6 +31,8 @@ module Hyrax
31
31
  return object if object.thumbnail_id == object.id ||
32
32
  object.try(:file_ids)&.detect { |fid| fid == object.thumbnail_id }
33
33
  begin
34
+ # In some implmentations (e.g. Wings), `find_by(id:)` aliases
35
+ # `find_by_alternate_identifier` but that is not guaranteed.
34
36
  return Hyrax.query_service.find_by(id: object.thumbnail_id)
35
37
  rescue
36
38
  nil
@@ -61,7 +61,7 @@ module Hyrax
61
61
 
62
62
  def process_works(stats, user, start_date)
63
63
  work_ids_for_user(user).each do |work_id|
64
- work = Hyrax::WorkRelation.new.find(work_id)
64
+ work = Hyrax.query_service.find_by(id: work_id)
65
65
  work_stats = extract_stats_for(object: work, from: WorkViewStat, start_date: start_date, user: user)
66
66
  stats = tally_results(work_stats, :work_views, stats) if work_stats.present?
67
67
  delay
@@ -94,7 +94,7 @@ module Hyrax
94
94
  if last_cached_stat
95
95
  last_cached_stat.date + 1.day
96
96
  else
97
- Hyrax.config.analytic_start_date
97
+ Hyrax.config.analytic_start_date || 1.week.ago
98
98
  end
99
99
  end
100
100
 
@@ -108,8 +108,8 @@ module Hyrax
108
108
 
109
109
  def work_ids_for_user(user)
110
110
  ids = []
111
- Hyrax::WorkRelation.new.search_in_batches("#{depositor_field}:\"#{user.user_key}\"", fl: "id") do |group|
112
- ids.concat group.map { |doc| doc["id"] }
111
+ Hyrax::SolrService.query_in_batches("#{depositor_field}:\"#{user.user_key}\"", fl: "id") do |hit|
112
+ ids << hit.id
113
113
  end
114
114
  ids
115
115
  end
@@ -124,7 +124,7 @@ module Hyrax
124
124
 
125
125
  date_key = stats.date.to_s
126
126
  old_count = total_stats[date_key] ? total_stats[date_key].fetch(stat_name) { 0 } : 0
127
- new_count = old_count + stats.method(stat_name).call
127
+ new_count = old_count + stats.method(stat_name).call.to_i
128
128
 
129
129
  old_values = total_stats[date_key] || {}
130
130
  total_stats.store(date_key, old_values)
@@ -18,10 +18,12 @@ class Hyrax::ValkyrieUpload
18
18
  io:,
19
19
  storage_adapter: Hyrax.storage_adapter,
20
20
  use: Hyrax::FileMetadata::Use::ORIGINAL_FILE,
21
- user: nil
21
+ user: nil,
22
+ mime_type: nil,
23
+ skip_derivatives: false
22
24
  )
23
25
  new(storage_adapter: storage_adapter)
24
- .upload(filename: filename, file_set: file_set, io: io, use: use, user: user)
26
+ .upload(filename: filename, file_set: file_set, io: io, use: use, user: user, mime_type: mime_type, skip_derivatives: skip_derivatives)
25
27
  end
26
28
 
27
29
  ##
@@ -36,13 +38,13 @@ class Hyrax::ValkyrieUpload
36
38
  @file_set_file_service = file_set_file_service
37
39
  end
38
40
 
39
- def upload(filename:, file_set:, io:, use: Hyrax::FileMetadata::Use::ORIGINAL_FILE, user: nil, mime_type: nil) # rubocop:disable Metrics/AbcSize
41
+ def upload(filename:, file_set:, io:, use: Hyrax::FileMetadata::Use::ORIGINAL_FILE, user: nil, mime_type: nil, skip_derivatives: false) # rubocop:disable Metrics/AbcSize
40
42
  return version_upload(file_set: file_set, io: io, user: user) if use == Hyrax::FileMetadata::Use::ORIGINAL_FILE && file_set.original_file_id && storage_adapter.supports?(:versions)
41
43
  streamfile = storage_adapter.upload(file: io, original_filename: filename, resource: file_set)
42
44
  file_metadata = Hyrax::FileMetadata(streamfile)
43
45
  file_metadata.file_set_id = file_set.id
44
- file_metadata.pcdm_use = [use]
45
- file_metadata.recorded_size = [io.size]
46
+ file_metadata.pcdm_use = Array(use)
47
+ file_metadata.recorded_size = Array(io.size)
46
48
  file_metadata.mime_type = mime_type if mime_type
47
49
  file_metadata.original_filename = File.basename(filename).to_s || File.basename(io)
48
50
 
@@ -62,8 +64,8 @@ class Hyrax::ValkyrieUpload
62
64
  file_metadata: saved_metadata,
63
65
  user: user)
64
66
 
65
- Hyrax.publisher.publish("file.uploaded", metadata: saved_metadata)
66
- Hyrax.publisher.publish('file.metadata.updated', metadata: saved_metadata, user: user)
67
+ Hyrax.publisher.publish("file.uploaded", metadata: saved_metadata, skip_derivatives: skip_derivatives)
68
+ Hyrax.publisher.publish('file.metadata.updated', metadata: saved_metadata, user: user, skip_derivatices: skip_derivatives)
67
69
 
68
70
  saved_metadata
69
71
  end
@@ -20,8 +20,16 @@ module Hyrax
20
20
 
21
21
  ##
22
22
  # @param resource [ActiveFedora::File | Hyrax::FileMetadata | NilClass]
23
- def initialize(resource:, storage_adapter: Hyrax.storage_adapter)
24
- @storage_adapter = storage_adapter
23
+ def initialize(resource:, storage_adapter: nil)
24
+ @storage_adapter = if storage_adapter.nil?
25
+ if resource.respond_to?(:file_identifier)
26
+ Valkyrie::StorageAdapter.adapter_for(id: resource.file_identifier)
27
+ else
28
+ Hyrax.storage_adapter
29
+ end
30
+ else
31
+ storage_adapter
32
+ end
25
33
  self.resource = resource
26
34
  end
27
35
 
@@ -3,7 +3,7 @@ module Hyrax
3
3
  # Responsible for retrieving information based on the given work.
4
4
  #
5
5
  # @see ProxyDepositRequest
6
- # @see Hyrax::WorkRelation
6
+ # @see Hyrax::VaklyrieWorkRelation
7
7
  # @see SolrDocument
8
8
  # @see Hyrax::SolrService
9
9
  # @see ActiveFedora::SolrQueryBuilder
@@ -20,7 +20,7 @@ module Hyrax
20
20
  private
21
21
 
22
22
  def default_work_relation
23
- Hyrax::WorkRelation.new
23
+ Hyrax.config.disable_wings ? Hyrax::ValkyrieWorkRelation.new : Hyrax::WorkRelation.new
24
24
  end
25
25
 
26
26
  public
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ # migrates models from AF to valkyrie
4
+ class MigrateResourceService
5
+ attr_accessor :resource
6
+ def initialize(resource:)
7
+ @resource = resource
8
+ end
9
+
10
+ def model
11
+ @model || Wings::ModelRegistry.lookup(resource.class).to_s
12
+ end
13
+
14
+ def call
15
+ prep_resource
16
+ Hyrax::Transactions::Container[model_events(model)]
17
+ .with_step_args(**model_steps(model)).call(resource_form)
18
+ end
19
+
20
+ def prep_resource
21
+ case model
22
+ when 'FileSet'
23
+ resource.creator << ::User.batch_user.email if resource.creator.blank?
24
+ end
25
+ end
26
+
27
+ def resource_form
28
+ @resource_form ||= Hyrax::Forms::ResourceForm.for(resource: resource)
29
+ end
30
+
31
+ def model_events(model)
32
+ {
33
+ 'AdminSet' => 'admin_set_resource.update',
34
+ 'Collection' => 'change_set.update_collection',
35
+ 'FileSet' => 'change_set.update_file_set'
36
+ }[model] || 'change_set.update_work'
37
+ end
38
+
39
+ def model_steps(model)
40
+ {
41
+ 'AdminSet' => {},
42
+ 'Collection' => {
43
+ 'collection_resource.save_collection_banner' => { banner_unchanged_indicator: true },
44
+ 'collection_resource.save_collection_logo' => { logo_unchanged_indicator: true }
45
+ },
46
+ 'FileSet' => {
47
+ 'file_set.save_acl' => {}
48
+ }
49
+ }[model] || {
50
+ 'work_resource.add_file_sets' => { uploaded_files: [], file_set_params: [] },
51
+ 'work_resource.update_work_members' => { work_members_attributes: [] },
52
+ 'work_resource.save_acl' => { permissions_params: [] }
53
+ }
54
+ end
55
+ end
@@ -1,12 +1,12 @@
1
- <nav class="navbar navbar-light bg-light navbar-expand-sm justify-content-between align-items-center px-2 py-3 border-bottom" role="navigation" aria-label="Root Menu">
1
+ <nav class="navbar bg-light navbar-expand-sm justify-content-between align-items-center px-2 py-3 border-bottom" role="navigation" aria-label="Root Menu">
2
2
  <ul class="nav navbar-nav col-sm-5">
3
- <li class="nav-item <%= 'active' if current_page?(hyrax.root_path) %>">
3
+ <li class="nav-item <%= 'active font-weight-bold' if current_page?(hyrax.root_path) %>">
4
4
  <%= link_to t(:'hyrax.controls.home'), hyrax.root_path, class: "nav-link", aria: current_page?(hyrax.root_path) ? {current: 'page'} : nil %></li>
5
- <li class="nav-item <%= 'active' if current_page?(hyrax.about_path) %>">
5
+ <li class="nav-item <%= 'active font-weight-bold' if current_page?(hyrax.about_path) %>">
6
6
  <%= link_to t(:'hyrax.controls.about'), hyrax.about_path, class: "nav-link", aria: current_page?(hyrax.about_path) ? {current: 'page'} : nil %></li>
7
- <li class="nav-item <%= 'active' if current_page?(hyrax.help_path) %>">
7
+ <li class="nav-item <%= 'active font-weight-bold' if current_page?(hyrax.help_path) %>">
8
8
  <%= link_to t(:'hyrax.controls.help'), hyrax.help_path, class: "nav-link", aria: current_page?(hyrax.help_path) ? {current: 'page'} : nil %></li>
9
- <li class="nav-item <%= 'active' if current_page?(hyrax.contact_path) %>">
9
+ <li class="nav-item <%= 'active font-weight-bold' if current_page?(hyrax.contact_path) %>">
10
10
  <%= link_to t(:'hyrax.controls.contact'), hyrax.contact_path, class: "nav-link", aria: current_page?(hyrax.contact_path) ? {current: 'page'} : nil %></li>
11
11
  </ul><!-- /.nav -->
12
12
  <div class="col-sm-7">
@@ -1,6 +1,6 @@
1
1
  <header aria-label="header" class="top-header">
2
2
  <nav id="masthead" class="navbar navbar-expand-lg navbar-dark bg-dark justify-content-between <%= placement_class %>" role="navigation" aria-label="masthead">
3
- <h1 class="sr-only"><%= application_name %></h1>
3
+ <h1 class="sr-only navbar-text"><%= application_name %></h1>
4
4
  <%= render '/logo' %>
5
5
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#top-navbar-collapse" aria-expanded="false" aria-label="Toggle navigation">
6
6
  <span class="navbar-toggler-icon"></span>
@@ -20,24 +20,17 @@
20
20
  <span class="sr-only" data-search-element="label"><%= t("hyrax.search.form.option.all.label_long", application_name: application_name) %></span>
21
21
  <span aria-hidden="true"><%= t("hyrax.search.form.option.all.label_short") %></span>
22
22
  </button>
23
-
24
- <ul class="dropdown-menu dropdown-menu-right">
25
- <li class="dropdown-item">
26
- <%= link_to t("hyrax.search.form.option.all.label_long", application_name: application_name), "#",
27
- data: { "search-option" => main_app.search_catalog_path, "search-label" => t("hyrax.search.form.option.all.label_short") } %>
28
- </li>
29
- <li class="dropdown-item">
30
- <%= link_to t("hyrax.search.form.option.my_works.label_long"), "#",
31
- data: { "search-option" => hyrax.my_works_path, "search-label" => t("hyrax.search.form.option.my_works.label_short") } %>
32
- </li>
33
- <li class="dropdown-item">
34
- <%= link_to t("hyrax.search.form.option.my_collections.label_long"), "#",
35
- data: { "search-option" => hyrax.my_collections_path, "search-label" => t("hyrax.search.form.option.my_collections.label_short") } %>
36
- </li>
37
- </ul>
23
+ <div class="dropdown-menu dropdown-menu-right">
24
+ <%= link_to t("hyrax.search.form.option.all.label_long", application_name: application_name), "#", class: "dropdown-item",
25
+ data: { "search-option" => main_app.search_catalog_path, "search-label" => t("hyrax.search.form.option.all.label_short") } %>
26
+ <%= link_to t("hyrax.search.form.option.my_works.label_long"), "#", class: "dropdown-item",
27
+ data: { "search-option" => hyrax.my_works_path, "search-label" => t("hyrax.search.form.option.my_works.label_short") } %>
28
+ <%= link_to t("hyrax.search.form.option.my_collections.label_long"), "#", class: "dropdown-item",
29
+ data: { "search-option" => hyrax.my_collections_path, "search-label" => t("hyrax.search.form.option.my_collections.label_short") } %>
30
+ </div>
38
31
  <% end %>
39
32
  </div><!-- /.input-group-btn -->
40
33
  </div><!-- /.input-group -->
41
-
34
+
42
35
  </div><!-- /.form-group -->
43
36
  <% end %>
@@ -1,4 +1,4 @@
1
1
  <div class="col-md-3">
2
- <%= document_presenter(document)&.thumbnail&.thumbnail_tag({}, { suppress_link: true }) %>
2
+ <%= document_presenter(document)&.thumbnail&.thumbnail_tag({ alt: document.title_or_label }, { suppress_link: true }) %>
3
3
  </div>
4
4
 
@@ -1,10 +1,10 @@
1
1
  <% model = document.hydra_model %>
2
2
  <div class="col-md-3">
3
3
  <% if model == Hyrax::PcdmCollection || model < Hyrax::PcdmCollection %>
4
- <%= document_presenter(document)&.thumbnail&.thumbnail_tag({}, suppress_link: true) %>
4
+ <%= document_presenter(document)&.thumbnail&.thumbnail_tag({ alt: document.title_or_label }, { suppress_link: true }) %>
5
5
  <% else %>
6
6
  <div class="list-thumbnail">
7
- <%= document_presenter(document)&.thumbnail&.thumbnail_tag %>
7
+ <%= document_presenter(document)&.thumbnail&.thumbnail_tag(alt: document.title_or_label) %>
8
8
  </div>
9
9
  <% end %>
10
10
  </div>
@@ -8,11 +8,11 @@
8
8
  <div class="col-sm-12">
9
9
  <div class="collection-reports">
10
10
 
11
- <% if Hyrax.config.analytics? %>
11
+ <% if Hyrax.config.analytics_reporting? %>
12
12
  <div class="card">
13
13
  <div class="card-header"><%= t('.repo_summary') %> <b><%= pluralize(Collection.count, "collection") %></b>, <%= t('.repo_summary_2') %> <b><%= @pageviews.all %> <%= t('.views') %></b> <%= t('.and') %> <b><%= @downloads.all %> <%= t('.downloads') %></b>.</div>
14
14
  <div class="card-body">
15
-
15
+
16
16
  <div class="row text-center">
17
17
  <div class="nav nav-pills btn-group" role="group">
18
18
  <% if params[:start_date] %>
@@ -54,7 +54,7 @@
54
54
  <%= render "hyrax/admin/analytics/date_range_form", redirect_path: hyrax.admin_analytics_collection_reports_path %>
55
55
  <%= render "custom_range" %></div>
56
56
  </div>
57
-
57
+
58
58
  </div>
59
59
  </div>
60
60
  <p class="text-center"><%= t('.report_generated_on') %> <b><%= Time.current %></b>.</p>
@@ -67,4 +67,4 @@
67
67
  <% end %>
68
68
  </div>
69
69
  </div>
70
- </div>
70
+ </div>
@@ -9,7 +9,7 @@
9
9
  <div class="work-reports">
10
10
 
11
11
  <div class="card">
12
- <% if Hyrax.config.analytics? %>
12
+ <% if Hyrax.config.analytics_reporting? %>
13
13
  <% if current_user.ability.admin? %>
14
14
  <div class="card-header"><b><%= @works_count %> <%= t('.works') %></b> <%= t('.repo_summary') %> <b><%= @pageviews.all if @pageviews %> <%= t('.views') %></b> <%= t('.and') %> <b><%= @downloads.all if @downloads %> <%= t('.downloads') %></b>.</div>
15
15
  <% else %>
@@ -1,17 +1,17 @@
1
1
  <%= render "shared/nav_safety_modal" %>
2
2
  <div class="card tabs" id="collection-types-controls">
3
3
  <ul class="nav nav-tabs" role="tablist">
4
- <li class="nav-item">
4
+ <li class="nav-item" role="presentation">
5
5
  <a href="#metadata" role="tab" data-toggle="tab" class="nav-link active nav-safety-confirm"><%= t('hyrax.admin.collection_types.form.tab.metadata') %></a>
6
6
  </li>
7
7
  <% if @form.persisted? %>
8
- <li class="nav-item">
8
+ <li class="nav-item" role="presentation">
9
9
  <a href="#settings" role="tab" data-toggle="tab" class="nav-link nav-safety-confirm"><%= t('hyrax.admin.collection_types.form.tab.settings') %></a>
10
10
  </li>
11
- <li class="nav-item">
11
+ <li class="nav-item" role="presentation">
12
12
  <a href="#participants" role="tab" data-toggle="tab" class="nav-link nav-safety-confirm"><%= t('hyrax.admin.collection_types.form.tab.participants') %></a>
13
13
  </li>
14
- <li class="nav-item">
14
+ <li class="nav-item" role="presentation">
15
15
  <a href="#appearance" role="tab" data-toggle="tab" class="nav-link nav-safety-confirm"><%= t('hyrax.admin.collection_types.form.tab.appearance') %></a>
16
16
  </li>
17
17
  <% end %>
@@ -41,7 +41,7 @@
41
41
  <button class="btn btn-danger btn-sm delete-collection-type"
42
42
  data-collection-type="<%= collection_type.to_json %>"
43
43
  data-collection-type-index="<%= hyrax.dashboard_collections_path({ 'f[collection_type_gid_ssim][]' => collection_type.to_global_id.to_s }) %>"
44
- data-has-collections="<%= collection_type.collections.any? %>">
44
+ data-has-collections="<%= collection_type.collections? %>">
45
45
  <%= t('helpers.action.delete') %>
46
46
  </button>
47
47
  <% end %>
@@ -9,7 +9,7 @@
9
9
  <table class="table table-striped">
10
10
  <thead>
11
11
  <tr>
12
- <th></th>
12
+ <th>Status</th>
13
13
  <th class="name"><%= t('.feature') %></th>
14
14
  <th class="description"><%= t('.description') %></th>
15
15
  <th class="action"><%= t('.action') %></th>
@@ -1,6 +1,6 @@
1
1
  <div class="actions card">
2
2
  <div class="d-flex">
3
- <%= button_tag t('.save'), class: "btn btn-primary disabled mr-2", data: { action: "save-actions" } %>
3
+ <%= button_tag t('.save'), class: "btn btn-primary disabled mr-2", data: { action: "save-actions" }, 'aria-disabled': true %>
4
4
  <%= button_tag t('.sort_alphabetically'), class: "btn btn-primary ", data: { action: "alpha-sort-action" } %>
5
5
  </div>
6
6
  </div>
@@ -3,7 +3,8 @@
3
3
  <%= simple_form_for [main_app, node], remote: true, html: {'data-type': 'json'} do |f| %>
4
4
  <div class="card-header">
5
5
  <div class="order-title">
6
- <%= f.input :title, as: :string, input_html: { name: "#{f.object.model_name.singular}[title][]", class: "title" }, value: node.to_s, label: false, hint: false %>
6
+ <label class="sr-only" id='<%= "edit_#{f.object.model_name.singular}_title" %>'>Edit title</label>
7
+ <%= f.input :title, as: :string, input_html: { name: "#{f.object.model_name.singular}[title][]", class: "title", 'aria-labelledby': "edit_#{f.object.model_name.singular}_title" }, value: node.to_s, label: false, hint: false %>
7
8
  </div>
8
9
  <div class="file-set-link float-right">
9
10
  <%= link_to contextual_path(node, @presenter), title: "Edit file" do %>
@@ -11,9 +12,11 @@
11
12
  <% end %>
12
13
  </div>
13
14
  <% if node.respond_to?(:label) %>
14
- <div class="order-filename">
15
- <em title="<%= node.page_title %>">(<%= truncate(node.label, length: 29) %>)</em>
16
- </div>
15
+ <% unless node.label.nil? %>
16
+ <div class="order-filename" >
17
+ <em title="<%= node.page_title %>">(<%= truncate(node.label, length: 29) %>)</em>
18
+ </div>
19
+ <% end %>
17
20
  <% end %>
18
21
  </div>
19
22
  <div class="card-body">
@@ -1 +1 @@
1
- <%= document_presenter(node)&.thumbnail&.thumbnail_tag({ class: 'thumbnail-inner mw-100' }, {}) %>
1
+ <%= document_presenter(node)&.thumbnail&.thumbnail_tag({ class: 'thumbnail-inner mw-100', 'alt': "Thumbnail image for #{node.title[0]}" }, {}) %>
@@ -1,4 +1,4 @@
1
- <%= render "base_form_files_prepend", locals: { f: f } %>
1
+ <%= render partial: "base_form_files_prepend", locals: { f: f } %>
2
2
  <div id="fileupload">
3
3
  <!-- Redirect browsers with JavaScript disabled to the origin page -->
4
4
  <noscript><input type="hidden" name="redirect" value="<%= main_app.root_path %>" /></noscript>
@@ -33,6 +33,10 @@ HTML Properties:
33
33
  </tr>
34
34
  </thead>
35
35
  <tbody>
36
+ <tr class="sr-only">
37
+ <td>This table will only display data if works are assigned to collections</td>
38
+ <td><span></span></td>
39
+ </tr>
36
40
  </tbody>
37
41
  </table>
38
42
  </div>
@@ -17,7 +17,7 @@
17
17
  class: presenter.display_unfeature_link? ? 'btn btn-secondary' : 'btn btn-secondary collapse' %>
18
18
  <% end %>
19
19
  <% end %>
20
- <% if Hyrax.config.analytics? %>
20
+ <% if Hyrax.config.analytics_reporting? %>
21
21
  <% # turbolinks needs to be turned off or the page will use the cache and the %>
22
22
  <% # analytics graph will not show unless the page is refreshed. %>
23
23
  <%= link_to t('.analytics'), presenter.stats_path, id: 'stats', class: 'btn btn-secondary', data: { turbolinks: false } %>
@@ -34,13 +34,12 @@
34
34
  <div class="btn-group">
35
35
  <button type="button" class="btn btn-secondary dropdown-toggle" type="button" id="dropdown-menu" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
36
36
  <%= t('.attach_child') %>
37
- <ul class="dropdown-menu">
38
- <% presenter.valid_child_concerns.each do |concern| %>
39
- <li class="dropdown-item">
40
- <%= link_to "Attach #{concern.human_readable_type}", polymorphic_path([main_app, :new, :hyrax, :parent, concern.model_name.singular.to_sym], parent_id: presenter.id) %>
41
- </li>
42
- <% end %>
43
- </ul>
37
+ </button>
38
+ <div class="dropdown-menu">
39
+ <% presenter.valid_child_concerns.each do |concern| %>
40
+ <%= link_to "Attach #{concern.human_readable_type}", polymorphic_path([main_app, :new, :hyrax, :parent, concern.model_name.singular.to_sym], parent_id: presenter.id), class: "dropdown-item" %>
41
+ <% end %>
42
+ </div>
44
43
  </div>
45
44
  <% end %>
46
45
  <%= link_to t('.delete'), [main_app, presenter], class: 'btn btn-danger', data: { confirm: t('.confirm_delete', work_type: presenter.human_readable_type) }, method: :delete %>
@@ -38,7 +38,7 @@
38
38
  data: { behavior: 'unfeature' },
39
39
  class: presenter.display_feature_link? ? 'btn btn-secondary collapse' : 'btn btn-secondary' %>
40
40
  <% end %>
41
- <% if Hyrax.config.analytics? %>
41
+ <% if Hyrax.config.analytics_reporting? %>
42
42
  <%= link_to t(".analytics"), presenter.stats_path, id: 'stats', class: 'btn btn-secondary' %>
43
43
  <% end %>
44
44
  </div>
@@ -1,3 +1,3 @@
1
1
  <div data-behavior="batch-add-button">
2
- <%= check_box_tag "batch_document_ids[]", document.id, false, class:"batch_document_selector", id: "batch_document_#{document.id}", checks: "active" %>
2
+ <%= check_box_tag "batch_document_ids[]", document.id, false, class:"batch_document_selector", id: "batch_document_#{document.id}", checks: "active", 'aria-labelledby': "batch_document_#{document.id}" %>
3
3
  </div>