bulkrax 9.3.5 → 9.4.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 (95) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -1
  3. data/app/assets/javascripts/bulkrax/application.js +2 -1
  4. data/app/assets/javascripts/bulkrax/bulkrax.js +13 -4
  5. data/app/assets/javascripts/bulkrax/bulkrax_utils.js +96 -0
  6. data/app/assets/javascripts/bulkrax/datatables.js +1 -0
  7. data/app/assets/javascripts/bulkrax/entries.js +17 -10
  8. data/app/assets/javascripts/bulkrax/importers.js.erb +9 -2
  9. data/app/assets/javascripts/bulkrax/importers_stepper.js +2420 -0
  10. data/app/assets/stylesheets/bulkrax/application.css +1 -1
  11. data/app/assets/stylesheets/bulkrax/stepper/_header.scss +83 -0
  12. data/app/assets/stylesheets/bulkrax/stepper/_mixins.scss +26 -0
  13. data/app/assets/stylesheets/bulkrax/stepper/_navigation.scss +103 -0
  14. data/app/assets/stylesheets/bulkrax/stepper/_responsive.scss +46 -0
  15. data/app/assets/stylesheets/bulkrax/stepper/_review.scss +92 -0
  16. data/app/assets/stylesheets/bulkrax/stepper/_settings.scss +106 -0
  17. data/app/assets/stylesheets/bulkrax/stepper/_success.scss +26 -0
  18. data/app/assets/stylesheets/bulkrax/stepper/_summary.scss +171 -0
  19. data/app/assets/stylesheets/bulkrax/stepper/_upload.scss +339 -0
  20. data/app/assets/stylesheets/bulkrax/stepper/_validation.scss +237 -0
  21. data/app/assets/stylesheets/bulkrax/stepper/_variables.scss +46 -0
  22. data/app/assets/stylesheets/bulkrax/stepper.scss +32 -0
  23. data/app/controllers/bulkrax/guided_imports_controller.rb +175 -0
  24. data/app/controllers/bulkrax/importers_controller.rb +28 -31
  25. data/app/controllers/concerns/bulkrax/guided_import_demo_scenarios.rb +201 -0
  26. data/app/controllers/concerns/bulkrax/importer_file_handler.rb +212 -0
  27. data/app/errors/bulkrax/unzip_error.rb +16 -0
  28. data/app/factories/bulkrax/object_factory.rb +3 -2
  29. data/app/factories/bulkrax/valkyrie_object_factory.rb +61 -17
  30. data/app/jobs/bulkrax/importer_job.rb +42 -4
  31. data/app/models/bulkrax/csv_entry.rb +27 -7
  32. data/app/models/bulkrax/entry.rb +4 -0
  33. data/app/models/bulkrax/importer.rb +27 -10
  34. data/app/models/concerns/bulkrax/has_matchers.rb +2 -2
  35. data/app/models/concerns/bulkrax/importer_exporter_behavior.rb +6 -5
  36. data/app/parsers/bulkrax/application_parser.rb +63 -20
  37. data/app/parsers/bulkrax/bagit_parser.rb +12 -0
  38. data/app/parsers/bulkrax/csv_parser.rb +168 -25
  39. data/app/parsers/concerns/bulkrax/csv_parser/csv_template_generation.rb +73 -0
  40. data/app/parsers/concerns/bulkrax/csv_parser/csv_validation.rb +133 -0
  41. data/app/parsers/concerns/bulkrax/csv_parser/csv_validation_helpers.rb +282 -0
  42. data/app/parsers/concerns/bulkrax/csv_parser/csv_validation_hierarchy.rb +96 -0
  43. data/app/services/bulkrax/csv_template/column_builder.rb +60 -0
  44. data/app/services/bulkrax/csv_template/column_descriptor.rb +58 -0
  45. data/app/services/bulkrax/csv_template/csv_builder.rb +83 -0
  46. data/app/services/bulkrax/csv_template/explanation_builder.rb +57 -0
  47. data/app/services/bulkrax/csv_template/field_analyzer.rb +56 -0
  48. data/app/services/bulkrax/csv_template/file_path_generator.rb +47 -0
  49. data/app/services/bulkrax/csv_template/file_validator.rb +68 -0
  50. data/app/services/bulkrax/csv_template/mapping_manager.rb +55 -0
  51. data/app/services/bulkrax/csv_template/model_loader.rb +50 -0
  52. data/app/services/bulkrax/csv_template/row_builder.rb +35 -0
  53. data/app/services/bulkrax/csv_template/schema_analyzer.rb +70 -0
  54. data/app/services/bulkrax/csv_template/split_formatter.rb +44 -0
  55. data/app/services/bulkrax/csv_template/value_determiner.rb +68 -0
  56. data/app/services/bulkrax/stepper_response_formatter.rb +347 -0
  57. data/app/services/bulkrax/validation_error_csv_builder.rb +99 -0
  58. data/app/validators/bulkrax/csv_row/child_reference.rb +56 -0
  59. data/app/validators/bulkrax/csv_row/circular_reference.rb +71 -0
  60. data/app/validators/bulkrax/csv_row/controlled_vocabulary.rb +74 -0
  61. data/app/validators/bulkrax/csv_row/duplicate_identifier.rb +63 -0
  62. data/app/validators/bulkrax/csv_row/missing_source_identifier.rb +31 -0
  63. data/app/validators/bulkrax/csv_row/parent_reference.rb +59 -0
  64. data/app/validators/bulkrax/csv_row/required_values.rb +64 -0
  65. data/app/views/bulkrax/guided_imports/new.html.erb +567 -0
  66. data/app/views/bulkrax/importers/index.html.erb +6 -1
  67. data/app/views/bulkrax/importers/new.html.erb +1 -1
  68. data/app/views/bulkrax/importers/show.html.erb +17 -1
  69. data/config/i18n-tasks.yml +195 -0
  70. data/config/locales/bulkrax.de.yml +508 -0
  71. data/config/locales/bulkrax.en.yml +463 -233
  72. data/config/locales/bulkrax.es.yml +508 -0
  73. data/config/locales/bulkrax.fr.yml +508 -0
  74. data/config/locales/bulkrax.it.yml +508 -0
  75. data/config/locales/bulkrax.pt-BR.yml +508 -0
  76. data/config/locales/bulkrax.zh.yml +507 -0
  77. data/config/routes.rb +10 -1
  78. data/lib/bulkrax/data/demo_scenarios.json +2235 -0
  79. data/lib/bulkrax/version.rb +1 -1
  80. data/lib/bulkrax.rb +31 -0
  81. metadata +56 -16
  82. data/app/services/bulkrax/sample_csv_service/column_builder.rb +0 -58
  83. data/app/services/bulkrax/sample_csv_service/column_descriptor.rb +0 -56
  84. data/app/services/bulkrax/sample_csv_service/csv_builder.rb +0 -82
  85. data/app/services/bulkrax/sample_csv_service/explanation_builder.rb +0 -51
  86. data/app/services/bulkrax/sample_csv_service/field_analyzer.rb +0 -54
  87. data/app/services/bulkrax/sample_csv_service/file_path_generator.rb +0 -16
  88. data/app/services/bulkrax/sample_csv_service/mapping_manager.rb +0 -36
  89. data/app/services/bulkrax/sample_csv_service/model_loader.rb +0 -40
  90. data/app/services/bulkrax/sample_csv_service/row_builder.rb +0 -33
  91. data/app/services/bulkrax/sample_csv_service/schema_analyzer.rb +0 -69
  92. data/app/services/bulkrax/sample_csv_service/split_formatter.rb +0 -42
  93. data/app/services/bulkrax/sample_csv_service/value_determiner.rb +0 -67
  94. data/app/services/bulkrax/sample_csv_service.rb +0 -78
  95. /data/{app/services → lib}/wings/custom_queries/find_by_source_identifier.rb +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d7205ae1ec1e6287a3afe95e94df9e3f7afcdb72ad0d6e934cca44004b28e8a4
4
- data.tar.gz: bae60650dc0ad54df42c9aa7da87829039462f6159c25b296a029c28f99006e8
3
+ metadata.gz: 420e0b83f78ad1c411b0532bda121bebe74a651a9d1abec51549273896a00bcb
4
+ data.tar.gz: 892e143d2de6c714121804bf547b9473545c1071ecce6ef9a6269cb60eeaf66f
5
5
  SHA512:
6
- metadata.gz: 7b81763a20e21c294bf0fa56479cafc506fdc589f31c11d3bbd0383b28fda247734f3abe4d0797e5601abd64815aa457ea8d908bfbf427a03fa5e500bbfe60d2
7
- data.tar.gz: e34566bafe813523345aaa41b2ad9fc2921e78be118250dfa911453fba185ea25cea6f74440fa6d5ddbb1dbcc699aca1f4ca5d3eb139c3dae65d27953de5f45d
6
+ metadata.gz: 497fe999aa3d39f3e7281b5e743a75d5b6c60ba93d0a7a40bd63bdfe248b0c35e52dffaa9b8aebe59489e68999ea9a0e22826ed30ffea0f2d8927cfaa61852d5
7
+ data.tar.gz: 176a04163d610ad5241b96ecd107ae4bc79e64dddaff94f2fa80b7b93ce48951934ffb8f4a3438169c185f7c5a6e9f468aa8371c3c1c3d282d7c9d59ebfde946
data/README.md CHANGED
@@ -195,6 +195,16 @@ Once your the exporter has run, a download icon will appear on the exporters men
195
195
  * Ruby 2.7 or newer is required
196
196
  * Hyrax 2.3 or newer is required
197
197
 
198
+ ## Translations
199
+
200
+ The [i18n-tasks gem](https://github.com/glebm/i18n-tasks) is a static analysis tool that helps manage Rails locale files. It scans the codebase for calls to `t()` and `I18n.t()` and creates a list of all the translation keys then compares that list against what actually exists in the locale files.
201
+
202
+ Useful commands:
203
+ - `bundle exec i18n-tasks` - a list of all tasks
204
+ - `i18n-tasks health` - check for unused keys and files that need formatting
205
+ - `i18n-tasks normalize` - sort and auto-format
206
+ - `i18n-tasks translate-missing` - creates missing translations; **NOTE**: requires a service such as Google Translate
207
+
198
208
  ## Contributing
199
209
  If you're working on a PR for this project, create a feature branch off of `main`.
200
210
 
@@ -204,7 +214,7 @@ See
204
214
  [CONTRIBUTING.md](https://github.com/samvera/bulkrax/blob/main/CONTRIBUTING.md)
205
215
  for contributing guidelines.
206
216
 
207
- We encourage everyone to help improve this project. Bug reports and pull requests are welcome on GitHub at https://github.com/samvera/bulkrax.
217
+ We encourage everyone to help improve this project. Bug reports and pull requests are welcome on GitHub at https://github.com/samvera/bulkrax. For guided import bugs, use the [Guided import bug report](https://github.com/samvera/bulkrax/issues/new?template=guided_import_bug_report.md) template.
208
218
 
209
219
  This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](https://contributor-covenant.org) code of conduct.
210
220
 
@@ -10,5 +10,6 @@
10
10
  // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
11
  // about supported directives.
12
12
  //
13
-
13
+ // IMPORTANT: bulkrax_utils must load first as other files depend on it
14
+ //= require bulkrax/bulkrax_utils
14
15
  //= require_tree .
@@ -1,16 +1,16 @@
1
1
  // Global JS file for Bulkrax
2
2
 
3
- $(document).on('turbolinks:load ready', function() {
3
+ function setupGlobalListeners() {
4
4
  // Apply to Importer and Exporter views
5
5
  $('button#err_toggle').click(function() {
6
6
  $('#error_trace').toggle();
7
7
  });
8
-
8
+
9
9
  $('button#fm_toggle').click(function() {
10
10
  $('#field_mapping').toggle();
11
11
  });
12
12
 
13
- $('#bulkraxItemModal').on('show.bs.modal', function (event) {
13
+ $('#bulkraxItemModal').on('show.bs.modal', function(event) {
14
14
  var button = $(event.relatedTarget); // Button that triggered the modal
15
15
  var recipient = button.data('entry-id'); // Extract info from data-* attributes
16
16
  // If necessary, you could initiate an AJAX request here (and then do the updating in a callback).
@@ -21,4 +21,13 @@ $(document).on('turbolinks:load ready', function() {
21
21
  });
22
22
  return true;
23
23
  });
24
- });
24
+ }
25
+
26
+ // Use Turbolinks if available, fallback to Turbo if available, fallback to vanilla JS if needed.
27
+ if (typeof Turbolinks !== 'undefined' && Turbolinks !== null) {
28
+ $(document).on('turbolinks:load ready', setupGlobalListeners);
29
+ } else if (typeof Turbo !== 'undefined') {
30
+ $(document).on('turbo:load ready', setupGlobalListeners);
31
+ } else {
32
+ $(document).on('ready', setupGlobalListeners);
33
+ }
@@ -0,0 +1,96 @@
1
+ // Bulkrax Utilities - Reusable helper functions
2
+ // Used across Bulkrax JavaScript modules
3
+
4
+ ; (function () {
5
+ 'use strict'
6
+
7
+ // Create namespace
8
+ window.BulkraxUtils = window.BulkraxUtils || {}
9
+
10
+ // ============================================================================
11
+ // HTML & STRING UTILITIES
12
+ // ============================================================================
13
+
14
+ /**
15
+ * Escape HTML to prevent XSS attacks
16
+ * @param {string} unsafe - Untrusted user input
17
+ * @returns {string} HTML-safe string
18
+ */
19
+ function escapeHtml(unsafe) {
20
+ if (!unsafe) return ''
21
+ return unsafe
22
+ .toString()
23
+ .replace(/&/g, '&')
24
+ .replace(/</g, '&lt;')
25
+ .replace(/>/g, '&gt;')
26
+ .replace(/"/g, '&quot;')
27
+ .replace(/'/g, '&#039;')
28
+ }
29
+
30
+ // ============================================================================
31
+ // FILE UTILITIES
32
+ // ============================================================================
33
+
34
+ /**
35
+ * Format file size in human-readable format
36
+ * @param {number} bytes - File size in bytes
37
+ * @returns {string} Formatted size (e.g., "1.5 MB")
38
+ */
39
+ function formatFileSize(bytes) {
40
+ if (bytes === 0) return '0 Bytes'
41
+ var k = 1024
42
+ var sizes = ['Bytes', 'KB', 'MB', 'GB']
43
+ var i = Math.floor(Math.log(bytes) / Math.log(k))
44
+ return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i]
45
+ }
46
+
47
+ // ============================================================================
48
+ // DATA NORMALIZATION
49
+ // ============================================================================
50
+
51
+ /**
52
+ * Normalize boolean or string boolean to actual boolean
53
+ * Handles both boolean types and string representations
54
+ * @param {boolean|string} value - Value to normalize
55
+ * @returns {boolean|null} true, false, or null if indeterminate
56
+ */
57
+ function normalizeBoolean(value) {
58
+ if (value === true || value === 'true') return true
59
+ if (value === false || value === 'false') return false
60
+ return null
61
+ }
62
+
63
+ // ============================================================================
64
+ // INTERNATIONALIZATION
65
+ // ============================================================================
66
+
67
+ /**
68
+ * Look up a translation key from BulkraxI18n and interpolate variables.
69
+ * Falls back to the key name if not found.
70
+ * @param {string} key - Translation key (e.g. 'file_upload_error')
71
+ * @param {Object} [vars] - Interpolation variables (e.g. {count: 5})
72
+ * @returns {string} Translated and interpolated string
73
+ */
74
+ function t(key, vars) {
75
+ var translations = window.BulkraxI18n || {}
76
+ var text = translations[key]
77
+ if (text == null) return key
78
+ if (vars) {
79
+ Object.keys(vars).forEach(function (k) {
80
+ text = text.replace(new RegExp('%\\{' + k + '\\}', 'g'), vars[k])
81
+ })
82
+ }
83
+ return text
84
+ }
85
+
86
+ // ============================================================================
87
+ // PUBLIC API
88
+ // ============================================================================
89
+
90
+ window.BulkraxUtils = {
91
+ escapeHtml: escapeHtml,
92
+ formatFileSize: formatFileSize,
93
+ normalizeBoolean: normalizeBoolean,
94
+ t: t
95
+ }
96
+ })()
@@ -45,6 +45,7 @@ Blacklight.onLoad(function() {
45
45
  "ajax": window.location.href.replace(/(\/importers)/, "$1/importer_table.json"),
46
46
  "pageLength": 30,
47
47
  "lengthMenu": [[30, 100, 200], [30, 100, 200]],
48
+ "order": [[2, 'desc']],
48
49
  "columns": [
49
50
  { "data": "name" },
50
51
  { "data": "status_message" },
@@ -1,15 +1,22 @@
1
- $( document ).on('turbolinks:load ready', function() {
2
-
3
- $( "button#entry_error" ).click(function() {
4
- $( "#error_trace" ).toggle();
1
+ function setupButtonToggles() {
2
+ $("button#entry_error").click(function() {
3
+ $("#error_trace").toggle();
5
4
  });
6
5
 
7
- $( "button#raw_button" ).click(function() {
8
- $( "#raw_metadata" ).toggle();
6
+ $("button#raw_button").click(function() {
7
+ $("#raw_metadata").toggle();
9
8
  });
10
9
 
11
- $( "button#parsed_button" ).click(function() {
12
- $( "#parsed_metadata" ).toggle();
10
+ $("button#parsed_button").click(function() {
11
+ $("#parsed_metadata").toggle();
13
12
  });
14
-
15
- })
13
+ }
14
+
15
+ // Use Turbolinks if available, fallback to Turbo if available, fallback to vanilla JS if needed.
16
+ if (typeof Turbolinks !== 'undefined' && Turbolinks !== null) {
17
+ $(document).on('turbolinks:load ready', setupButtonToggles());
18
+ } else if (typeof Turbo !== 'undefined') {
19
+ $(document).on('turbo:load ready', setupButtonToggles());
20
+ } else {
21
+ $(document).on('DOMContentLoaded', setupButtonToggles());
22
+ }
@@ -3,7 +3,7 @@
3
3
 
4
4
  function prepBulkrax(event) {
5
5
  if($('form#new_importer, form.edit_importer').length < 1) {
6
- return true;
6
+ return;
7
7
  }
8
8
 
9
9
  var refresh_button = $('.refresh-set-source');
@@ -247,4 +247,11 @@ function setError(selector, error) {
247
247
  selector.attr('disabled', true);
248
248
  }
249
249
 
250
- $(document).on({'ready': prepBulkrax, 'turbolinks:load': prepBulkrax});
250
+ // Use Turbolinks if available, fallback to Turbo if available, fallback to jQuery if needed.
251
+ if (typeof Turbolinks !== 'undefined' && Turbolinks !== null) {
252
+ $(document).on('turbolinks:load', prepBulkrax);
253
+ } else if (typeof Turbo !== 'undefined') {
254
+ $(document).on('turbo:load', prepBulkrax);
255
+ } else {
256
+ $(document).ready(prepBulkrax);
257
+ }