geoblacklight_admin 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (162) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +24 -11
  3. data/Rakefile +83 -47
  4. data/app/assets/javascripts/geoblacklight_admin/chosen.js +1 -0
  5. data/app/assets/stylesheets/geoblacklight_admin/_core.scss +24 -0
  6. data/app/assets/stylesheets/geoblacklight_admin/modules/_nav.scss +0 -5
  7. data/app/assets/stylesheets/geoblacklight_admin/modules/_tables.scss +1 -1
  8. data/app/controllers/admin/admin_controller.rb +16 -0
  9. data/app/controllers/admin/advanced_search_controller.rb +7 -1
  10. data/app/controllers/admin/assets_controller.rb +47 -32
  11. data/app/controllers/admin/bookmarks_controller.rb +17 -5
  12. data/app/controllers/admin/bulk_actions_controller.rb +32 -1
  13. data/app/controllers/admin/document_accesses_controller.rb +38 -0
  14. data/app/controllers/admin/document_assets_controller.rb +47 -89
  15. data/app/controllers/admin/document_distributions_controller.rb +172 -0
  16. data/app/controllers/admin/documents_controller.rb +43 -57
  17. data/app/controllers/admin/elements_controller.rb +24 -0
  18. data/app/controllers/admin/form_elements_controller.rb +33 -0
  19. data/app/controllers/admin/ids_controller.rb +6 -0
  20. data/app/controllers/admin/import_documents_controller.rb +11 -1
  21. data/app/controllers/admin/imports_controller.rb +34 -4
  22. data/app/controllers/admin/mappings_controller.rb +15 -0
  23. data/app/controllers/admin/notifications_controller.rb +27 -0
  24. data/app/controllers/admin/reference_types_controller.rb +106 -0
  25. data/app/controllers/admin/search_controller.rb +7 -0
  26. data/app/controllers/admin/users_controller.rb +10 -0
  27. data/app/helpers/asset_helper.rb +6 -0
  28. data/app/helpers/bulk_actions_helper.rb +10 -1
  29. data/app/helpers/document_helper.rb +36 -0
  30. data/app/helpers/geoblacklight_admin_helper.rb +88 -8
  31. data/app/helpers/mappings_helper.rb +26 -0
  32. data/app/indexers/document_indexer.rb +22 -2
  33. data/app/javascript/channels/consumer.js +6 -0
  34. data/app/javascript/channels/export_channel.js +30 -0
  35. data/app/javascript/channels/index.js +3 -0
  36. data/app/javascript/controllers/results_controller.js +14 -0
  37. data/app/javascript/index.js +8 -2
  38. data/app/jobs/bulk_action_revert_document_job.rb +4 -12
  39. data/app/jobs/bulk_action_run_document_job.rb +2 -10
  40. data/app/jobs/export_job.rb +35 -8
  41. data/app/jobs/geoblacklight_admin/delete_thumbnail_job.rb +19 -0
  42. data/app/jobs/geoblacklight_admin/remove_parent_dct_references_uri_job.rb +16 -0
  43. data/app/jobs/geoblacklight_admin/set_parent_dct_references_uri_job.rb +17 -0
  44. data/app/jobs/geoblacklight_admin/store_image_job.rb +22 -0
  45. data/app/jobs/import_document_job.rb +1 -4
  46. data/app/jobs/import_run_job.rb +1 -1
  47. data/app/models/admin/bookmark.rb +1 -1
  48. data/app/models/asset.rb +20 -0
  49. data/app/models/bulk_action.rb +2 -1
  50. data/app/models/bulk_actions/change_publication_state.rb +0 -25
  51. data/app/models/bulk_actions/delete_thumbnails.rb +6 -0
  52. data/app/models/bulk_actions/draft_document.rb +6 -0
  53. data/app/models/bulk_actions/harvest_thumbnails.rb +6 -0
  54. data/app/models/bulk_actions/publish_document.rb +6 -0
  55. data/app/models/bulk_actions/unpublish_document.rb +6 -0
  56. data/app/models/document/geom_validator.rb +8 -0
  57. data/app/models/document/reference.rb +65 -65
  58. data/app/models/document.rb +129 -72
  59. data/app/models/document_distribution.rb +145 -0
  60. data/app/models/element.rb +2 -0
  61. data/app/models/geoblacklight_admin/schema.rb +10 -2
  62. data/app/models/import/csv_duplicates_validator.rb +2 -0
  63. data/app/models/import/csv_header_validator.rb +3 -1
  64. data/app/models/import_btaa_aardvark.rb +2 -2
  65. data/app/models/import_document_state_machine.rb +1 -0
  66. data/app/models/import_gblv1.rb +2 -2
  67. data/app/models/reference_type.rb +40 -0
  68. data/app/models/user.rb +4 -2
  69. data/app/services/export_csv_document_distributions_service.rb +61 -0
  70. data/app/services/geoblacklight_admin/image_service/iiif_manifest.rb +39 -43
  71. data/app/services/geoblacklight_admin/image_service/tms.rb +0 -8
  72. data/app/services/geoblacklight_admin/image_service.rb +1 -1
  73. data/app/services/geoblacklight_admin/item_viewer.rb +4 -4
  74. data/app/views/admin/bookmarks/index.html.erb +19 -14
  75. data/app/views/admin/bulk_actions/show.html.erb +1 -1
  76. data/app/views/admin/document_accesses/import.html.erb +6 -2
  77. data/app/views/admin/document_assets/_assets_table.html.erb +49 -0
  78. data/app/views/admin/document_assets/_form.html.erb +2 -3
  79. data/app/views/admin/document_assets/index.html.erb +1 -47
  80. data/app/views/admin/document_distributions/_document_distribution.html.erb +39 -0
  81. data/app/views/admin/document_distributions/_document_distribution.json.jbuilder +2 -0
  82. data/app/views/admin/document_distributions/_form.html.erb +34 -0
  83. data/app/views/admin/document_distributions/destroy_all.html.erb +82 -0
  84. data/app/views/admin/document_distributions/edit.html.erb +12 -0
  85. data/app/views/admin/document_distributions/import.html.erb +80 -0
  86. data/app/views/admin/document_distributions/index.html.erb +143 -0
  87. data/app/views/admin/document_distributions/index.json.jbuilder +1 -0
  88. data/app/views/admin/document_distributions/new.html.erb +11 -0
  89. data/app/views/admin/document_distributions/show.html.erb +10 -0
  90. data/app/views/admin/document_distributions/show.json.jbuilder +1 -0
  91. data/app/views/admin/documents/_document.html.erb +1 -3
  92. data/app/views/admin/documents/_form.html.erb +2 -4
  93. data/app/views/admin/documents/_form_control.html.erb +5 -2
  94. data/app/views/admin/documents/_form_nav.html.erb +14 -5
  95. data/app/views/admin/documents/_form_nav_kithe.html.erb +4 -1
  96. data/app/views/admin/documents/_json_aardvark.jbuilder +1 -1
  97. data/app/views/admin/documents/_json_gbl_v1.jbuilder +1 -1
  98. data/app/views/admin/documents/_result_selected_options.html.erb +5 -2
  99. data/app/views/admin/documents/admin.html.erb +5 -5
  100. data/app/views/admin/documents/features/_document_references.html.erb +23 -0
  101. data/app/views/admin/documents/features/_multiple_download_links.html.erb +29 -26
  102. data/app/views/admin/ids/fetch.json.jbuilder +0 -2
  103. data/app/views/admin/ids/index.json.jbuilder +0 -2
  104. data/app/views/admin/imports/_form.html.erb +1 -1
  105. data/app/views/admin/imports/show.html.erb +1 -1
  106. data/app/views/admin/layouts/application.html.erb +4 -2
  107. data/app/views/admin/mappings/index.html.erb +1 -1
  108. data/app/views/admin/notifications/_notification.html.haml +29 -28
  109. data/app/views/admin/reference_types/_form.html.erb +25 -0
  110. data/app/views/admin/reference_types/_reference_type.html.erb +52 -0
  111. data/app/views/admin/reference_types/_reference_type.json.jbuilder +2 -0
  112. data/app/views/admin/reference_types/edit.html.erb +12 -0
  113. data/app/views/admin/reference_types/index.html.erb +52 -0
  114. data/app/views/admin/reference_types/index.json.jbuilder +1 -0
  115. data/app/views/admin/reference_types/new.html.erb +11 -0
  116. data/app/views/admin/reference_types/show.html.erb +3 -0
  117. data/app/views/admin/reference_types/show.json.jbuilder +1 -0
  118. data/app/views/admin/shared/_footer.html.erb +5 -2
  119. data/app/views/admin/shared/_js_behaviors.html.erb +2 -3
  120. data/app/views/admin/shared/_navbar.html.erb +9 -2
  121. data/app/views/admin/users/index.html.erb +0 -1
  122. data/app/views/catalog/_show_gbl_admin.html.erb +1 -1
  123. data/config/initializers/defaults.yml +310 -0
  124. data/config/initializers/rails_config.rb +8 -0
  125. data/config/locales/documents.en.yml +14 -0
  126. data/config/routes.rb +30 -5
  127. data/db/import_references_schema_support.numbers +0 -0
  128. data/db/migrate/20230316183001_add_geoblacklight_admin_gem.rb +0 -12
  129. data/db/migrate/20241009200524_create_admin_reference_types.rb +13 -0
  130. data/db/migrate/20241010161420_create_document_references.rb +14 -0
  131. data/db/migrate/20241120238823_rename_references_to_distributions.rb +5 -0
  132. data/db/seeds.rb +5 -0
  133. data/db/seeds_elements.csv +1 -1
  134. data/db/seeds_elements.numbers +0 -0
  135. data/db/seeds_reference_types.csv +29 -0
  136. data/db/seeds_reference_types.numbers +0 -0
  137. data/db/structure.sql +1 -38
  138. data/lib/compose.yml +31 -0
  139. data/lib/generators/geoblacklight_admin/config_generator.rb +53 -12
  140. data/lib/generators/geoblacklight_admin/install_generator.rb +8 -0
  141. data/lib/generators/geoblacklight_admin/templates/btaa_sample_records.csv +5 -0
  142. data/lib/generators/geoblacklight_admin/templates/config/database.yml +1 -1
  143. data/lib/generators/geoblacklight_admin/templates/config/initializers/devise.rb +0 -2
  144. data/lib/generators/geoblacklight_admin/templates/config/initializers/mime_types.rb +1 -0
  145. data/lib/generators/geoblacklight_admin/templates/demo-app/Dockerfile +31 -0
  146. data/lib/generators/geoblacklight_admin/templates/demo-app/compose.yml +42 -0
  147. data/lib/generators/geoblacklight_admin/templates/demo-app/start-server.sh +21 -0
  148. data/lib/geoblacklight_admin/engine.rb +4 -0
  149. data/lib/geoblacklight_admin/rake_task.rb +2 -0
  150. data/lib/geoblacklight_admin/tasks/distributions.rake +69 -0
  151. data/lib/geoblacklight_admin/tasks/images.rake +1 -0
  152. data/lib/geoblacklight_admin/tasks/solr.rake +31 -0
  153. data/lib/geoblacklight_admin/version.rb +1 -1
  154. data/lib/geoblacklight_admin.rb +4 -0
  155. metadata +137 -53
  156. data/app/helpers/import_documents_helper.rb +0 -5
  157. data/app/javascript/entrypoints/engine.js +0 -8
  158. data/config/locales/devise_invitable.en.yml +0 -31
  159. data/lib/generators/geoblacklight_admin/templates/devise/invitations/edit.html.erb +0 -15
  160. data/lib/generators/geoblacklight_admin/templates/devise/invitations/new.html.erb +0 -15
  161. data/lib/generators/geoblacklight_admin/templates/devise/mailer/invitation_instructions.html.erb +0 -11
  162. data/lib/generators/geoblacklight_admin/templates/devise/mailer/invitation_instructions.text.erb +0 -11
@@ -1,14 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Admin::NotificationsController
4
+ #
5
+ # This controller manages the notifications for the admin panel. It provides
6
+ # actions to list, update, destroy, and batch update notifications.
4
7
  module Admin
5
8
  class NotificationsController < Admin::AdminController
6
9
  before_action :set_notification, only: %i[update destroy]
7
10
 
11
+ # GET /admin/notifications
12
+ #
13
+ # Lists all notifications for the current user, paginated.
14
+ #
15
+ # @return [void]
8
16
  def index
9
17
  @pagy, @notifications = pagy(current_user.notifications.order(created_at: :desc), items: 20)
10
18
  end
11
19
 
20
+ # PATCH/PUT /admin/notifications/:id
21
+ #
22
+ # Updates the read status of a notification.
23
+ #
24
+ # @param [String] read The read status, "0" for unread, "1" for read.
25
+ # @return [void]
12
26
  def update
13
27
  case params[:read]
14
28
  when "0"
@@ -25,6 +39,11 @@ module Admin
25
39
  end
26
40
  end
27
41
 
42
+ # DELETE /admin/notifications/:id
43
+ #
44
+ # Destroys a notification and purges its associated file.
45
+ #
46
+ # @return [void]
28
47
  def destroy
29
48
  @notification.file.purge
30
49
  @notification.destroy
@@ -34,6 +53,11 @@ module Admin
34
53
  end
35
54
  end
36
55
 
56
+ # POST /admin/notifications/batch
57
+ #
58
+ # Marks all notifications as read.
59
+ #
60
+ # @return [void]
37
61
  def batch
38
62
  return unless params[:read] == "all"
39
63
 
@@ -44,6 +68,9 @@ module Admin
44
68
 
45
69
  private
46
70
 
71
+ # Sets the notification based on the provided ID.
72
+ #
73
+ # @return [void]
47
74
  def set_notification
48
75
  @notification = Notification.find(params[:id])
49
76
  end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Admin::ReferenceTypesController
4
+ #
5
+ # This controller manages the CRUD operations for ReferenceType objects
6
+ # within the admin namespace. It includes actions to list, show, create,
7
+ # update, and destroy reference types, as well as a custom sort action.
8
+ class Admin::ReferenceTypesController < Admin::AdminController
9
+ before_action :set_reference_type, only: %i[show edit update destroy]
10
+
11
+ # GET /admin/reference_types or /admin/reference_types.json
12
+ #
13
+ # Lists all reference types.
14
+ def index
15
+ @reference_types = ReferenceType.all
16
+ end
17
+
18
+ # GET /admin/reference_types/1 or /admin/reference_types/1.json
19
+ #
20
+ # Shows a specific reference type.
21
+ def show
22
+ end
23
+
24
+ # GET /admin/reference_types/new
25
+ #
26
+ # Initializes a new reference type.
27
+ def new
28
+ @reference_type = ReferenceType.new
29
+ end
30
+
31
+ # GET /admin/reference_types/1/edit
32
+ #
33
+ # Edits an existing reference type.
34
+ def edit
35
+ end
36
+
37
+ # POST /admin/reference_types or /admin/reference_types.json
38
+ #
39
+ # Creates a new reference type. If successful, redirects to the show page
40
+ # of the newly created reference type. Otherwise, re-renders the new form.
41
+ def create
42
+ @reference_type = ReferenceType.new(reference_type_params)
43
+
44
+ respond_to do |format|
45
+ if @reference_type.save
46
+ format.html { redirect_to admin_reference_type_path(@reference_type), notice: "Reference type was successfully created." }
47
+ format.json { render :show, status: :created, location: @reference_type }
48
+ else
49
+ format.html { render :new, status: :unprocessable_entity }
50
+ format.json { render json: @reference_type.errors, status: :unprocessable_entity }
51
+ end
52
+ end
53
+ end
54
+
55
+ # PATCH/PUT /admin/reference_types/1 or /admin/reference_types/1.json
56
+ #
57
+ # Updates an existing reference type. If successful, redirects to the show
58
+ # page of the updated reference type. Otherwise, re-renders the edit form.
59
+ def update
60
+ respond_to do |format|
61
+ if @reference_type.update(reference_type_params)
62
+ format.html { redirect_to admin_reference_type_path(@reference_type), notice: "Reference type was successfully updated." }
63
+ format.json { render :show, status: :ok, location: @reference_type }
64
+ else
65
+ format.html { render :edit, status: :unprocessable_entity }
66
+ format.json { render json: @reference_type.errors, status: :unprocessable_entity }
67
+ end
68
+ end
69
+ end
70
+
71
+ # DELETE /admin/reference_types/1 or /admin/reference_types/1.json
72
+ #
73
+ # Destroys a reference type. Redirects to the index page with a notice.
74
+ def destroy
75
+ @reference_type.destroy!
76
+
77
+ respond_to do |format|
78
+ format.html { redirect_to admin_reference_types_path, status: :see_other, notice: "Reference type was successfully destroyed." }
79
+ format.json { head :no_content }
80
+ end
81
+ end
82
+
83
+ # POST /admin/reference_types/sort
84
+ #
85
+ # Sorts reference types based on the provided list of IDs.
86
+ def sort
87
+ ReferenceType.sort_elements(params[:id_list])
88
+ render body: nil
89
+ end
90
+
91
+ private
92
+
93
+ # Use callbacks to share common setup or constraints between actions.
94
+ #
95
+ # Sets the @reference_type instance variable for actions that require it.
96
+ def set_reference_type
97
+ @reference_type = ReferenceType.find(params[:id])
98
+ end
99
+
100
+ # Only allow a list of trusted parameters through.
101
+ #
102
+ # Permits the parameters required for creating or updating a reference type.
103
+ def reference_type_params
104
+ params.require(:reference_type).permit(:name, :reference_type, :reference_uri, :label, :note, :position)
105
+ end
106
+ end
@@ -1,8 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Admin::SearchController
4
+ # This controller handles search-related actions for the admin interface.
4
5
  module Admin
5
6
  class SearchController < Admin::AdminController
7
+ # GET /admin/search
8
+ #
9
+ # This action sets up the request URL and retrieves facet options
10
+ # from the Blacklight API.
11
+ #
12
+ # @return [void]
6
13
  def index
7
14
  @request = "#{request.protocol}#{request.host}:#{request.port}"
8
15
  @facet_options = BlacklightApiFacets.new(@request).facets
@@ -1,8 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Admin::UsersController
4
+ #
5
+ # This controller handles the actions related to admin users.
6
+ # It inherits from Admin::AdminController, which provides
7
+ # common functionality for all admin-related controllers.
4
8
  module Admin
5
9
  class UsersController < Admin::AdminController
10
+ # GET /admin/users
11
+ #
12
+ # This action retrieves all users with admin privileges.
13
+ # It assigns the result to the @users instance variable,
14
+ # which can be used in the corresponding view to display
15
+ # the list of admin users.
6
16
  def index
7
17
  @users = User.where(admin: true)
8
18
  end
@@ -1,7 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # AssetHelper
4
+ #
5
+ # This module provides helper methods for asset management.
4
6
  module AssetHelper
7
+ # Determines if an asset has a thumbnail to render.
8
+ #
9
+ # @param asset [Object] The asset object to check.
10
+ # @return [Boolean] Returns true if the asset has a file URL and file derivatives present, otherwise false.
5
11
  def asset_thumb_to_render?(asset)
6
12
  asset&.file_url&.present? && asset&.file_derivatives&.present?
7
13
  end
@@ -1,9 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # BulkActionsHelper
4
+ #
5
+ # This module provides helper methods for handling bulk actions
6
+ # within the GeoblacklightAdmin application.
4
7
  module BulkActionsHelper
8
+ # Returns a collection of attributes that can be used for bulk actions.
9
+ #
10
+ # The collection includes all importable fields from the GeoblacklightAdmin
11
+ # schema, with "Publication State" prepended to the list.
12
+ #
13
+ # @return [Array<String>] an array of attribute names
5
14
  def bulk_actions_collection
6
- attrs = Geomg.field_mappings.collect { |key, _value| key }
15
+ attrs = GeoblacklightAdmin::Schema.instance.importable_fields.collect { |key, _value| key }
7
16
  attrs.prepend("Publication State")
8
17
  end
9
18
  end
@@ -1,7 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # DocumentHelper
4
+ #
5
+ # This module provides helper methods for handling document-related
6
+ # functionalities such as generating publication state badges, creating
7
+ # localized links, and handling pagination links.
4
8
  module DocumentHelper
9
+ # Generates a badge for the publication state of a document.
10
+ #
11
+ # @param document [Object] the document object containing the publication state
12
+ # @return [String] HTML link with a span element representing the publication state
5
13
  def publication_state_badge(document)
6
14
  case document.publication_state
7
15
  when "draft"
@@ -19,15 +27,27 @@ module DocumentHelper
19
27
  end
20
28
  end
21
29
 
30
+ # Localizes a given link by parsing its URI and appending it to a base path.
31
+ #
32
+ # @param link [String] the link to be localized
33
+ # @return [String] the localized link
22
34
  def localize_link(link)
23
35
  uri = URI.parse(link)
24
36
  "/admin/documents?#{uri.query}"
25
37
  end
26
38
 
39
+ # Creates a sort link with a label and localized URL.
40
+ #
41
+ # @param link [Hash] a hash containing link attributes and self link
42
+ # @return [String] HTML link element for sorting
27
43
  def sort_link(link)
28
44
  link_to link["attributes"]["label"], localize_link(link["links"]["self"]), {class: "dropdown-item"}
29
45
  end
30
46
 
47
+ # Processes a link from an API response, determining whether to add or remove a facet.
48
+ #
49
+ # @param link [Hash] a hash containing links for adding or removing facets
50
+ # @return [Hash] a hash with action and link keys
31
51
  def link_from_api(link)
32
52
  # Append facet - Full URI returned
33
53
  uri = URI.parse(link["links"]["self"])
@@ -38,6 +58,10 @@ module DocumentHelper
38
58
  {action: "remove", link: "/admin/documents?#{uri.query}"}
39
59
  end
40
60
 
61
+ # Generates a link to the previous page in a paginated list.
62
+ #
63
+ # @param links [Hash] a hash containing pagination links
64
+ # @return [String] HTML link element for the previous page
41
65
  def previous_link(links)
42
66
  if links["prev"]
43
67
  link_to "Previous", localize_link(links["prev"]), {class: "btn btn-outline-primary btn-sm"}
@@ -46,6 +70,10 @@ module DocumentHelper
46
70
  end
47
71
  end
48
72
 
73
+ # Generates a link to the next page in a paginated list.
74
+ #
75
+ # @param links [Hash] a hash containing pagination links
76
+ # @return [String] HTML link element for the next page
49
77
  def next_link(links)
50
78
  if links["next"]
51
79
  link_to "Next", localize_link(links["next"]), {class: "btn btn-outline-primary btn-sm"}
@@ -54,10 +82,18 @@ module DocumentHelper
54
82
  end
55
83
  end
56
84
 
85
+ # Constructs a link to a document's page in the Blacklight catalog.
86
+ #
87
+ # @param document [Object] the document object
88
+ # @return [String] the URL to the document's Blacklight catalog page
57
89
  def blacklight_link(document)
58
90
  "#{BLACKLIGHT_URL}/catalog/#{document.friendlier_id}"
59
91
  end
60
92
 
93
+ # Determines if a document's thumbnail should be rendered.
94
+ #
95
+ # @param document [Object] the document object
96
+ # @return [Boolean] true if the thumbnail should be rendered, false otherwise
61
97
  def thumb_to_render?(document)
62
98
  document&.thumbnail&.file_url&.present? && document&.thumbnail&.file_derivatives&.present?
63
99
  end
@@ -1,13 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # GeoblacklightAdminHelper
4
+ #
5
+ # This module provides helper methods for the GeoBlacklight admin interface.
6
+ # It includes methods for handling JSON data, generating paths, formatting
7
+ # flash messages, and more.
4
8
  module GeoblacklightAdminHelper
5
9
  # @TODO:
6
10
  # Cannot generate app if uncommented...
7
11
  # Uncomment after app is generated to fix view errors
8
12
  include ::Pagy::Frontend if defined?(Pagy)
9
13
 
10
- # jbuilder helper
14
+ # Removes blank values from JSON data.
15
+ #
16
+ # @param value [String, Array] the value to check for presence
17
+ # @return [String, Array, nil] the original value if present, otherwise nil
11
18
  def no_json_blanks(value)
12
19
  case value
13
20
  when String
@@ -17,17 +24,21 @@ module GeoblacklightAdminHelper
17
24
  end
18
25
  end
19
26
 
20
- # qa (questioning_authoriry) gem oddly gives us no route helpers, so
21
- # let's make one ourselves, for it's current mount point, we can change
22
- # it if needed but at least it's DRY.
27
+ # Generates a search path for the QA (questioning_authority) gem.
28
+ #
29
+ # @param vocab [String] the vocabulary to search
30
+ # @param subauthority [String, nil] the subauthority to search
31
+ # @return [String] the generated search path
23
32
  def qa_search_vocab_path(vocab, subauthority = nil)
24
33
  path = "/authorities/search/#{CGI.escape vocab}"
25
-
26
34
  path += "/#{CGI.escape subauthority}" if subauthority
27
-
28
35
  path
29
36
  end
30
37
 
38
+ # Maps flash message levels to CSS classes.
39
+ #
40
+ # @param level [String] the flash message level
41
+ # @return [String] the corresponding CSS class
31
42
  def flash_class(level)
32
43
  alerts = {
33
44
  "notice" => "alert alert-info",
@@ -38,6 +49,9 @@ module GeoblacklightAdminHelper
38
49
  alerts[level]
39
50
  end
40
51
 
52
+ # Provides a mapping of institution codes to institution names.
53
+ #
54
+ # @return [Hash] a hash mapping institution codes to names
41
55
  def b1g_institution_codes
42
56
  {
43
57
  "01" => "Indiana University",
@@ -58,11 +72,17 @@ module GeoblacklightAdminHelper
58
72
  }
59
73
  end
60
74
 
75
+ # Generates an HTML badge for bookmarks.
76
+ #
77
+ # @return [String] the HTML string for the bookmarks badge
61
78
  def bookmarks_badge
62
79
  bookmarks_classes = ["badge", "badge-dark"]
63
80
  "<span class='#{bookmarks_classes.join(" ")}' id='bookmarks-count'>#{current_user.bookmarks.size}</span>"
64
81
  end
65
82
 
83
+ # Generates an HTML badge for notifications.
84
+ #
85
+ # @return [String] the HTML string for the notifications badge
66
86
  def notifications_badge
67
87
  notifications_classes = ["badge"]
68
88
  notifications_classes << "badge-dark" if current_user.notifications.unread.empty?
@@ -70,7 +90,10 @@ module GeoblacklightAdminHelper
70
90
  "<span class='#{notifications_classes.join(" ")}' id='notification-count'>#{current_user.notifications.unread.size}</span>"
71
91
  end
72
92
 
73
- # From Blacklight::HiddenSearchStateComponent
93
+ # Converts parameters into hidden form fields.
94
+ #
95
+ # @param params [Hash] the parameters to convert
96
+ # @return [String] the HTML string of hidden fields
74
97
  def params_as_hidden_fields(params)
75
98
  hidden_fields = []
76
99
  flatten_hash(params).each do |name, value|
@@ -83,6 +106,12 @@ module GeoblacklightAdminHelper
83
106
  safe_join(hidden_fields, "\n")
84
107
  end
85
108
 
109
+ # Flattens a nested hash into a single-level hash with keys representing the
110
+ # nested structure.
111
+ #
112
+ # @param hash [Hash] the hash to flatten
113
+ # @param ancestor_names [Array] the ancestor keys for nested hashes
114
+ # @return [Hash] the flattened hash
86
115
  def flatten_hash(hash, ancestor_names = [])
87
116
  flat_hash = {}
88
117
  hash.each do |k, v|
@@ -100,6 +129,10 @@ module GeoblacklightAdminHelper
100
129
  flat_hash
101
130
  end
102
131
 
132
+ # Generates a key for a flattened hash from an array of names.
133
+ #
134
+ # @param names [Array] the array of names
135
+ # @return [String] the generated key
103
136
  def flat_hash_key(names)
104
137
  names = Array.new(names)
105
138
  name = names.shift.to_s.dup
@@ -109,6 +142,10 @@ module GeoblacklightAdminHelper
109
142
  name
110
143
  end
111
144
 
145
+ # Maps a character to a CSS class for diff highlighting.
146
+ #
147
+ # @param char [String] the character representing a diff operation
148
+ # @return [String] the corresponding CSS class
112
149
  def diff_class(char)
113
150
  case char
114
151
  when "~"
@@ -122,6 +159,10 @@ module GeoblacklightAdminHelper
122
159
  end
123
160
  end
124
161
 
162
+ # Generates a link to the admin import page for a given import.
163
+ #
164
+ # @param import [Object] the import object
165
+ # @return [String] the HTML link to the admin import page
125
166
  def link_to_admin_import(import)
126
167
  path = admin_documents_path(
127
168
  {
@@ -132,6 +173,12 @@ module GeoblacklightAdminHelper
132
173
  link_to import.name, path
133
174
  end
134
175
 
176
+ # Generates a link to the GeoBlacklight import page with optional state.
177
+ #
178
+ # @param label [String] the link label
179
+ # @param import [Object] the import object
180
+ # @param state [Boolean] the publication state
181
+ # @return [String] the HTML link to the GeoBlacklight import page
135
182
  def link_to_gbl_import(label, import, state = false)
136
183
  path = if state
137
184
  blacklight_path(
@@ -152,7 +199,40 @@ module GeoblacklightAdminHelper
152
199
  link_to(label, path)
153
200
  end
154
201
 
202
+ # Generates options for asset DCT references.
203
+ #
204
+ # @return [String] the escaped JavaScript string of options
155
205
  def assets_dct_references_options
156
- escape_javascript(options_for_select(I18n.t("activemodel.enum_values.document/reference.category").invert.sort.insert(0, ["Choose Reference Type", nil]))).to_s
206
+ escape_javascript(options_for_select(I18n.t("activemodel.asset_enum_values.document/reference.category").invert.sort.insert(0, ["Choose Reference Type", nil]))).to_s
207
+ end
208
+
209
+ # Determines if a document's thumbnail should be rendered.
210
+ #
211
+ # @param document [Object] the document object
212
+ # @return [Boolean] true if the thumbnail should be rendered, false otherwise
213
+ def thumb_to_render?(document)
214
+ if document&.thumbnail&.file_url&.present? && document&.thumbnail&.file_derivatives&.present?
215
+ true
216
+ elsif document&.document_assets&.any?
217
+ document.document_assets.any? do |asset|
218
+ asset.file_derivatives&.key?(:thumb_standard_2X)
219
+ end
220
+ else
221
+ false
222
+ end
223
+ end
224
+
225
+ # Returns the URL of the thumbnail to render for a document.
226
+ #
227
+ # @param document [Object] the document object
228
+ # @return [String] the URL of the thumbnail to render
229
+ def thumbnail_to_render(document)
230
+ if document&.thumbnail&.file_url&.present? && document&.thumbnail&.file_derivatives&.present?
231
+ document.thumbnail.file_url(:thumb_standard_2X)
232
+ elsif document&.document_assets&.any?
233
+ document.document_assets.find do |asset|
234
+ asset.file_derivatives&.key?(:thumb_standard_2X)
235
+ end&.file_url(:thumb_standard_2X)
236
+ end
157
237
  end
158
238
  end
@@ -1,7 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # MappingsHelper
4
+ #
5
+ # This module provides helper methods for handling mappings in the application.
6
+ # It includes methods to generate attribute collections and provide mapping
7
+ # and delimiter suggestions based on import configurations.
4
8
  module MappingsHelper
9
+ # Returns a collection of attributes that can be used for mapping.
10
+ #
11
+ # The collection is generated from importable elements, sorted, and includes
12
+ # additional options for an empty string and "Discard".
13
+ #
14
+ # @return [Array<String>] a sorted array of attribute names with additional options.
5
15
  def attribute_collection
6
16
  attrs = Element.importable.map(&:solr_field).sort
7
17
  attrs.prepend("")
@@ -9,6 +19,14 @@ module MappingsHelper
9
19
  attrs
10
20
  end
11
21
 
22
+ # Provides a mapping suggestion for a given header based on the import configuration.
23
+ #
24
+ # Checks if the header is included in the import's mapping configuration and returns
25
+ # the destination if available.
26
+ #
27
+ # @param import [Object] the import object containing mapping configurations.
28
+ # @param header [String] the header for which the mapping suggestion is needed.
29
+ # @return [String, false] the destination mapping if available, otherwise false.
12
30
  def mapping_suggestion(import, header)
13
31
  if import.mapping_configuration.include?(header.to_sym)
14
32
  import.mapping_configuration[header.to_sym][:destination]
@@ -17,6 +35,14 @@ module MappingsHelper
17
35
  end
18
36
  end
19
37
 
38
+ # Provides a delimiter suggestion for a given header based on the import configuration.
39
+ #
40
+ # Checks if the header is included in the import's mapping configuration and returns
41
+ # the delimiter if available.
42
+ #
43
+ # @param import [Object] the import object containing mapping configurations.
44
+ # @param header [String] the header for which the delimiter suggestion is needed.
45
+ # @return [String, false] the delimiter if available, otherwise false.
20
46
  def delimiter_suggestion(import, header)
21
47
  if import.mapping_configuration.include?(header.to_sym)
22
48
  import.mapping_configuration[header.to_sym][:delimited]
@@ -1,6 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Solr indexing for our document class. Still a work in progress.
4
+ #
5
+ # The DocumentIndexer class is responsible for configuring how documents
6
+ # are indexed into Solr. It uses the Kithe::Indexer framework to map
7
+ # document attributes to Solr fields.
8
+ #
9
+ # The configuration block defines various fields that are indexed, including
10
+ # fields specific to GeoBlacklight and custom fields defined via the Element model.
11
+ #
12
+ # Fields:
13
+ # - model_pk_ssi: The primary key of the model, extracted from the object's ID.
14
+ # - gbl_mdVersion_s: A static version string for GeoBlacklight.
15
+ # - gbl_mdModified_dt: The modification date of the metadata.
16
+ # - date_created_dtsi: The creation date of the record, in UTC ISO8601 format.
17
+ # - date_modified_dtsi: The last modification date of the record, in UTC ISO8601 format.
18
+ # - b1g_geom_import_id_ssi: The import ID for GeoBlacklight administration.
19
+ #
20
+ # If the "elements" table exists, additional fields are indexed based on
21
+ # the Element model's configuration.
4
22
  class DocumentIndexer < Kithe::Indexer
5
23
  configure do
6
24
  # Kithe
@@ -12,8 +30,10 @@ class DocumentIndexer < Kithe::Indexer
12
30
  # to_field 'geomg_id_s', obj_extract('friendlier_id') # the actual db pk, a UUID
13
31
 
14
32
  # Define `to_field`(s) via Element
15
- Element.indexable.each do |elm|
16
- to_field elm.solr_field, obj_extract(elm.index_value)
33
+ if ActiveRecord::Base.connection.table_exists?("elements")
34
+ Element.indexable.each do |elm|
35
+ to_field elm.solr_field, obj_extract(elm.index_value)
36
+ end
17
37
  end
18
38
 
19
39
  to_field "gbl_mdModified_dt", obj_extract("gbl_mdModified_dt")
@@ -0,0 +1,6 @@
1
+ // Action Cable provides the framework to deal with WebSockets in Rails.
2
+ // You can generate new channels where WebSocket features live using the `bin/rails generate channel` command.
3
+
4
+ import { createConsumer } from "@rails/actioncable"
5
+
6
+ export default createConsumer()
@@ -0,0 +1,30 @@
1
+ import consumer from "./consumer"
2
+
3
+ consumer.subscriptions.create({ channel: "ExportChannel" }, {
4
+ connected() {
5
+ // Called when the subscription is ready for use on the server
6
+ console.log("GBL Admin - ExportChannel connected");
7
+ },
8
+
9
+ disconnected() {
10
+ // Called when the subscription has been terminated by the server
11
+ console.log("GBL Admin - ExportChannel disconnected");
12
+ },
13
+
14
+ received(data) {
15
+ console.log('GBL Admin - ExportChannel received!');
16
+ console.log(data);
17
+
18
+ if (data['progress']) {
19
+ console.log(data['progress']);
20
+ }
21
+
22
+ if (data['actions']) {
23
+ for (let index = 0; index < data.actions.length; ++index) {
24
+ var fnstring = data.actions[index].method;
25
+ var fn = window["GBLADMIN"][fnstring];
26
+ if (typeof fn === "function") fn(data.actions[index].payload);
27
+ }
28
+ }
29
+ }
30
+ });
@@ -0,0 +1,3 @@
1
+ export { default as consumer } from './consumer';
2
+ export { default as exportChannel } from './export_channel';
3
+ export { default as index } from './index';
@@ -12,6 +12,7 @@ import { Controller } from "stimulus"
12
12
  export default class extends Controller {
13
13
 
14
14
  connect() {
15
+ console.log("GBL Admin - ResultsController connected");
15
16
  }
16
17
 
17
18
  checkedState(checked, selector='input[type=checkbox]') {
@@ -228,6 +229,7 @@ export default class extends Controller {
228
229
  }
229
230
 
230
231
  exportCsvDocumentDownloads() {
232
+ console.log('Export - CsvDocumentDownloads')
231
233
  var scope = this.checkSelectionScope();
232
234
  var el = document.querySelector('#result-selected-options');
233
235
  if(scope === 'pageset') {
@@ -238,6 +240,7 @@ export default class extends Controller {
238
240
  }
239
241
 
240
242
  exportCsvDocumentAccessLinks() {
243
+ console.log('Export - CsvDocumentAccessLinks')
241
244
  var scope = this.checkSelectionScope();
242
245
  var el = document.querySelector('#result-selected-options');
243
246
  if(scope === 'pageset') {
@@ -247,6 +250,17 @@ export default class extends Controller {
247
250
  }
248
251
  }
249
252
 
253
+ exportCsvDocumentDistributions() {
254
+ console.log('Export - CsvDocumentDistributions')
255
+ var scope = this.checkSelectionScope();
256
+ var el = document.querySelector('#result-selected-options');
257
+ if(scope === 'pageset') {
258
+ window.location = el.dataset.pageset + "&format=csv_document_distributions"
259
+ } else {
260
+ window.location = el.dataset.resultset + "&format=csv_document_distributions"
261
+ }
262
+ }
263
+
250
264
  bulkAction() {
251
265
  var scope = this.checkSelectionScope();
252
266
  var el = document.querySelector('#result-selected-options');