bulkrax 6.0.1 → 8.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +7 -7
  3. data/app/assets/javascripts/bulkrax/bulkrax.js +11 -0
  4. data/app/assets/javascripts/bulkrax/datatables.js +139 -0
  5. data/app/assets/javascripts/bulkrax/exporters.js +4 -4
  6. data/app/assets/javascripts/bulkrax/importers.js.erb +15 -1
  7. data/app/assets/stylesheets/bulkrax/import_export.scss +6 -1
  8. data/app/controllers/bulkrax/entries_controller.rb +52 -3
  9. data/app/controllers/bulkrax/exporters_controller.rb +20 -8
  10. data/app/controllers/bulkrax/importers_controller.rb +31 -12
  11. data/app/controllers/concerns/bulkrax/datatables_behavior.rb +201 -0
  12. data/app/factories/bulkrax/object_factory.rb +135 -163
  13. data/app/factories/bulkrax/object_factory_interface.rb +491 -0
  14. data/app/factories/bulkrax/valkyrie_object_factory.rb +402 -0
  15. data/app/helpers/bulkrax/application_helper.rb +7 -3
  16. data/app/helpers/bulkrax/importers_helper.rb +1 -1
  17. data/app/helpers/bulkrax/validation_helper.rb +4 -4
  18. data/app/jobs/bulkrax/create_relationships_job.rb +28 -17
  19. data/app/jobs/bulkrax/delete_and_import_collection_job.rb +8 -0
  20. data/app/jobs/bulkrax/delete_and_import_file_set_job.rb +8 -0
  21. data/app/jobs/bulkrax/delete_and_import_job.rb +20 -0
  22. data/app/jobs/bulkrax/delete_and_import_work_job.rb +8 -0
  23. data/app/jobs/bulkrax/delete_job.rb +8 -3
  24. data/app/jobs/bulkrax/download_cloud_file_job.rb +17 -4
  25. data/app/jobs/bulkrax/import_collection_job.rb +1 -1
  26. data/app/jobs/bulkrax/import_file_set_job.rb +6 -3
  27. data/app/jobs/bulkrax/import_job.rb +7 -0
  28. data/app/jobs/bulkrax/import_work_job.rb +1 -1
  29. data/app/jobs/bulkrax/importer_job.rb +19 -3
  30. data/app/matchers/bulkrax/application_matcher.rb +0 -2
  31. data/app/models/bulkrax/csv_collection_entry.rb +1 -3
  32. data/app/models/bulkrax/csv_entry.rb +9 -7
  33. data/app/models/bulkrax/entry.rb +9 -11
  34. data/app/models/bulkrax/exporter.rb +11 -4
  35. data/app/models/bulkrax/importer.rb +49 -10
  36. data/app/models/bulkrax/oai_entry.rb +0 -3
  37. data/app/models/bulkrax/oai_set_entry.rb +1 -3
  38. data/app/models/bulkrax/rdf_collection_entry.rb +1 -4
  39. data/app/models/bulkrax/rdf_entry.rb +70 -69
  40. data/app/models/bulkrax/status.rb +10 -1
  41. data/app/models/bulkrax/xml_entry.rb +0 -1
  42. data/app/models/concerns/bulkrax/dynamic_record_lookup.rb +2 -19
  43. data/app/models/concerns/bulkrax/export_behavior.rb +2 -2
  44. data/app/models/concerns/bulkrax/file_factory.rb +174 -118
  45. data/app/models/concerns/bulkrax/file_set_entry_behavior.rb +5 -3
  46. data/app/models/concerns/bulkrax/has_matchers.rb +28 -25
  47. data/app/models/concerns/bulkrax/import_behavior.rb +14 -33
  48. data/app/models/concerns/bulkrax/importer_exporter_behavior.rb +3 -2
  49. data/app/models/concerns/bulkrax/status_info.rb +8 -0
  50. data/app/parsers/bulkrax/application_parser.rb +116 -21
  51. data/app/parsers/bulkrax/bagit_parser.rb +173 -195
  52. data/app/parsers/bulkrax/csv_parser.rb +15 -57
  53. data/app/parsers/bulkrax/oai_dc_parser.rb +44 -16
  54. data/app/parsers/bulkrax/parser_export_record_set.rb +20 -24
  55. data/app/parsers/bulkrax/xml_parser.rb +18 -23
  56. data/app/services/bulkrax/factory_class_finder.rb +92 -0
  57. data/app/services/bulkrax/remove_relationships_for_importer.rb +3 -1
  58. data/app/services/hyrax/custom_queries/find_by_source_identifier.rb +50 -0
  59. data/app/services/wings/custom_queries/find_by_source_identifier.rb +32 -0
  60. data/app/views/bulkrax/entries/_parsed_metadata.html.erb +2 -2
  61. data/app/views/bulkrax/entries/_raw_metadata.html.erb +2 -2
  62. data/app/views/bulkrax/entries/show.html.erb +9 -8
  63. data/app/views/bulkrax/exporters/_form.html.erb +10 -10
  64. data/app/views/bulkrax/exporters/edit.html.erb +1 -1
  65. data/app/views/bulkrax/exporters/index.html.erb +13 -57
  66. data/app/views/bulkrax/exporters/new.html.erb +1 -1
  67. data/app/views/bulkrax/exporters/show.html.erb +6 -12
  68. data/app/views/bulkrax/importers/_browse_everything.html.erb +2 -2
  69. data/app/views/bulkrax/importers/_csv_fields.html.erb +8 -2
  70. data/app/views/bulkrax/importers/_edit_form_buttons.html.erb +8 -1
  71. data/app/views/bulkrax/importers/_edit_item_buttons.html.erb +18 -0
  72. data/app/views/bulkrax/importers/edit.html.erb +1 -1
  73. data/app/views/bulkrax/importers/index.html.erb +20 -64
  74. data/app/views/bulkrax/importers/new.html.erb +1 -1
  75. data/app/views/bulkrax/importers/show.html.erb +8 -14
  76. data/app/views/bulkrax/importers/upload_corrected_entries.html.erb +2 -2
  77. data/app/views/bulkrax/shared/_bulkrax_errors.html.erb +1 -1
  78. data/app/views/bulkrax/shared/_bulkrax_field_mapping.html.erb +1 -1
  79. data/app/views/bulkrax/shared/_entries_tab.html.erb +16 -0
  80. data/config/locales/bulkrax.en.yml +7 -0
  81. data/config/routes.rb +8 -2
  82. data/db/migrate/20230608153601_add_indices_to_bulkrax.rb +20 -9
  83. data/db/migrate/20240208005801_denormalize_status_message.rb +7 -0
  84. data/db/migrate/20240209070952_update_identifier_index.rb +6 -0
  85. data/db/migrate/20240307053156_add_index_to_metadata_bulkrax_identifier.rb +18 -0
  86. data/lib/bulkrax/engine.rb +23 -0
  87. data/lib/bulkrax/version.rb +1 -1
  88. data/lib/bulkrax.rb +107 -19
  89. data/lib/generators/bulkrax/templates/config/initializers/bulkrax.rb +2 -0
  90. data/lib/tasks/bulkrax_tasks.rake +13 -0
  91. data/lib/tasks/reset.rake +4 -4
  92. metadata +64 -8
  93. data/app/views/bulkrax/shared/_collection_entries_tab.html.erb +0 -39
  94. data/app/views/bulkrax/shared/_file_set_entries_tab.html.erb +0 -39
  95. data/app/views/bulkrax/shared/_work_entries_tab.html.erb +0 -39
@@ -33,13 +33,14 @@
33
33
 
34
34
  <p class='bulkrax-p-align'>
35
35
  <% if @importer.present? %>
36
+ <%# TODO Consider how to account for Bulkrax.collection_model_class %>
36
37
  <% factory_record = @entry.factory.find %>
37
38
  <% if factory_record.present? && @entry.factory_class %>
38
- <strong><%= @entry.factory_class.to_s %> Link:</strong>
39
- <% if @entry.factory_class.to_s == 'Collection' %>
40
- <%= link_to @entry.factory_class.to_s, hyrax.polymorphic_path(factory_record) %>
39
+ <strong><%= @entry.factory_class.model_name.human %> Link:</strong>
40
+ <% if defined?(Hyrax) && @entry.factory_class.model_name.human == 'Collection' %>
41
+ <%= link_to @entry.factory_class.model_name.human, hyrax.polymorphic_path(factory_record) %>
41
42
  <% else %>
42
- <%= link_to @entry.factory_class.to_s, main_app.polymorphic_path(factory_record) %>
43
+ <%= link_to @entry.factory_class.model_name.human, main_app.polymorphic_path(factory_record) %>
43
44
  <% end %>
44
45
  <% else %>
45
46
  <strong>Item Link:</strong> Item has not yet been imported successfully
@@ -47,11 +48,11 @@
47
48
  <% else %>
48
49
  <% record = @entry&.hyrax_record %>
49
50
  <% if record.present? && @entry.factory_class %>
50
- <strong><%= record.class.to_s %> Link:</strong>
51
- <% if defined?(Collection) && record.is_a?(Collection) %>
52
- <%= link_to record.class.to_s, hyrax.polymorphic_path(record) %>
51
+ <strong><%= record.model_name.human %> Link:</strong>
52
+ <% if defined?(Hyrax) && record.model_name.human == "Collection" %>
53
+ <%= link_to record.model_name.human, hyrax.polymorphic_path(record) %>
53
54
  <% else %>
54
- <%= link_to record.class.to_s, main_app.polymorphic_path(record) %>
55
+ <%= link_to record.model_name.human, main_app.polymorphic_path(record) %>
55
56
  <% end %>
56
57
  <% else %>
57
58
  <strong>Item Link:</strong> No item associated with this entry or class unknown
@@ -33,8 +33,8 @@
33
33
  label: t('bulkrax.exporter.labels.importer'),
34
34
  required: true,
35
35
  prompt: 'Select from the list',
36
- label_html: { class: 'importer export-source-option d-none' },
37
- input_html: { class: 'importer export-source-option d-none form-control' },
36
+ label_html: { class: 'importer export-source-option d-none hidden' },
37
+ input_html: { class: 'importer export-source-option d-none hidden form-control' },
38
38
  collection: form.object.importers_list.sort %>
39
39
 
40
40
  <%= form.input :export_source_collection,
@@ -42,9 +42,9 @@
42
42
  label: t('bulkrax.exporter.labels.collection'),
43
43
  required: true,
44
44
  placeholder: @collection&.title&.first,
45
- label_html: { class: 'collection export-source-option d-none' },
45
+ label_html: { class: 'collection export-source-option d-none hidden' },
46
46
  input_html: {
47
- class: 'collection export-source-option d-none form-control',
47
+ class: 'collection export-source-option d-none hidden form-control',
48
48
  data: {
49
49
  'autocomplete-url' => '/authorities/search/collections',
50
50
  'autocomplete' => 'collection'
@@ -56,8 +56,8 @@
56
56
  label: t('bulkrax.exporter.labels.worktype'),
57
57
  required: true,
58
58
  prompt: 'Select from the list',
59
- label_html: { class: 'worktype export-source-option d-none' },
60
- input_html: { class: 'worktype export-source-option d-none form-control' },
59
+ label_html: { class: 'worktype export-source-option d-none hidden' },
60
+ input_html: { class: 'worktype export-source-option d-none hidden form-control' },
61
61
  collection: Bulkrax.curation_concerns.map { |cc| [cc.to_s, cc.to_s] } %>
62
62
 
63
63
  <%= form.input :limit,
@@ -80,7 +80,7 @@
80
80
  as: :boolean,
81
81
  label: t('bulkrax.exporter.labels.filter_by_date') %>
82
82
 
83
- <div id="date_filter_picker" class="d-none">
83
+ <div id="date_filter_picker" class="d-none hidden">
84
84
  <%= form.input :start_date,
85
85
  as: :date,
86
86
  label: t('bulkrax.exporter.labels.start_date'),
@@ -136,13 +136,13 @@
136
136
  // get the date filter option and show the corresponding date selectors
137
137
  $('.exporter_date_filter').change(function () {
138
138
  if ($('.exporter_date_filter').find(".boolean").is(":checked"))
139
- $('#date_filter_picker').removeClass('d-none');
139
+ $('#date_filter_picker').removeClass('d-none hidden');
140
140
  else
141
- $('#date_filter_picker').addClass('d-none');
141
+ $('#date_filter_picker').addClass('d-none hidden');
142
142
  });
143
143
 
144
144
  if ($('.exporter_date_filter').find(".boolean").is(":checked"))
145
- $('#date_filter_picker').removeClass('d-none');
145
+ $('#date_filter_picker').removeClass('d-none hidden');
146
146
  });
147
147
  });
148
148
  </script>
@@ -14,7 +14,7 @@
14
14
  <%= form.button :submit, value: 'Update and Re-Export All Items', class: 'btn btn-primary' %>
15
15
  |
16
16
  <% cancel_path = form.object.persisted? ? exporter_path(form.object) : exporters_path %>
17
- <%= link_to t('.cancel'), cancel_path, class: 'btn btn-default ' %>
17
+ <%= link_to t('bulkrax.cancel'), cancel_path, class: 'btn btn-default ' %>
18
18
  </div>
19
19
  </div>
20
20
  <% end %>
@@ -13,62 +13,18 @@
13
13
 
14
14
  <div class="panel panel-default">
15
15
  <div class="panel-body">
16
- <% if @exporters.present? %>
17
- <div class="table-responsive">
18
- <table class="table table-striped datatable">
19
- <thead>
20
- <tr>
21
- <th scope="col">Name</th>
22
- <th scope="col">Status</th>
23
- <th scope="col">Date Exported</th>
24
- <th scope="col">Downloadable Files</th>
25
- <th scope="col"></th>
26
- <th scope="col"></th>
27
- <th scope="col"></th>
28
- </tr>
29
- </thead>
30
- <tbody>
31
- <% @exporters.each do |exporter| %>
32
- <tr>
33
- <th scope="row"><%= link_to exporter.name, exporter_path(exporter) %></th>
34
- <td><%= exporter.status %></td>
35
- <td><%= exporter.created_at %></td>
36
- <td>
37
- <% if File.exist?(exporter.exporter_export_zip_path) %>
38
- <%= simple_form_for(exporter, method: :get, url: exporter_download_path(exporter)) do |form| %>
39
- <%= render 'downloads', exporter: exporter, form: form %>
40
- <%= form.button :submit, value: 'Download', data: { disable_with: false } %>
41
- <% end %>
42
- <% end%>
43
- </td>
44
- <td><%= link_to raw('<span class="glyphicon glyphicon-info-sign"></span>'), exporter_path(exporter) %></td>
45
- <td><%= link_to raw('<span class="glyphicon glyphicon-pencil"></span>'), edit_exporter_path(exporter), data: { turbolinks: false } %></td>
46
- <td><%= link_to raw('<span class="glyphicon glyphicon-remove"></span>'), exporter, method: :delete, data: { confirm: 'Are you sure?' } %></td>
47
- </tr>
48
- <% end %>
49
- </tbody>
50
- </table>
51
- </div>
52
- <% else %>
53
- <p>No exporters have been created.</p>
54
- <% end %>
16
+ <div class="table-responsive">
17
+ <table id='exporters-table' class="table table-striped">
18
+ <thead>
19
+ <tr>
20
+ <th scope="col">Name</th>
21
+ <th scope="col">Status</th>
22
+ <th scope="col">Date Exported</th>
23
+ <th scope="col">Downloadable Files</th>
24
+ <th scope="col">Actions</th>
25
+ </tr>
26
+ </thead>
27
+ </table>
28
+ </div>
55
29
  </div>
56
30
  </div>
57
-
58
- <script>
59
- $(function() {
60
- $('#DataTables_Table_0').DataTable({
61
- destroy: true, /* Reinitialize DataTable with config below */
62
- 'columnDefs': [
63
- { 'orderable': true, 'targets': [0, 1, 2] },
64
- { 'orderable': false, 'targets': [3, 4, 5, 6] }
65
- ],
66
- 'language': {
67
- 'info': 'Showing _START_ to _END_ of _TOTAL_ exporters',
68
- 'infoEmpty': 'No exporters to show',
69
- 'infoFiltered': '(filtered from _MAX_ total exporters)',
70
- 'lengthMenu': 'Show _MENU_ exporters'
71
- }
72
- })
73
- })
74
- </script>
@@ -14,7 +14,7 @@
14
14
  <%= form.button :submit, value: 'Create', class: 'btn btn-primary' %>
15
15
  |
16
16
  <% cancel_path = form.object.persisted? ? exporter_path(form.object) : exporters_path %>
17
- <%= link_to t('.cancel'), cancel_path, class: 'btn btn-default ' %>
17
+ <%= link_to t('bulkrax.cancel'), cancel_path, class: 'btn btn-default ' %>
18
18
  </div>
19
19
  </div>
20
20
  <% end %>
@@ -39,8 +39,10 @@
39
39
  <strong><%= t('bulkrax.exporter.labels.export_source') %>:</strong>
40
40
  <% case @exporter.export_from %>
41
41
  <% when 'collection' %>
42
- <% collection = Collection.find(@exporter.export_source) %>
43
- <%= link_to collection&.title&.first, hyrax.dashboard_collection_path(collection.id) %>
42
+ <% collection = Bulkrax.object_factory.find_or_nil(@exporter.export_source) %>
43
+ <% id = collection&.id || @exporter.export_source %>
44
+ <% title = collection&.title&.first || @exporter.export_source %>
45
+ <%= link_to title, hyrax.dashboard_collection_path(id) %>
44
46
  <% when 'importer' %>
45
47
  <% importer = Bulkrax::Importer.find(@exporter.export_source) %>
46
48
  <%= link_to importer.name, bulkrax.importer_path(importer.id) %>
@@ -95,16 +97,8 @@
95
97
 
96
98
  <div class="bulkrax-nav-tab-bottom-margin">
97
99
  <!-- Nav tabs -->
98
- <ul class="bulkrax-nav-tab-top-margin tab-nav nav nav-tabs" role="tablist">
99
- <li role="presentation" class="nav-link active"><a href="#work-entries" aria-controls="work-entries" role="tab" data-toggle="tab"><%= t('bulkrax.exporter.labels.work_entries') %></a></li>
100
- <li role="presentation" class="nav-link"><a href="#collection-entries" aria-controls="collection-entries" role="tab" data-toggle="tab"><%= t('bulkrax.exporter.labels.collection_entries') %></a></li>
101
- <li role="presentation" class="nav-link"><a href="#file-set-entries" aria-controls="file-set-entries" role="tab" data-toggle="tab"><%= t('bulkrax.exporter.labels.file_set_entries') %></a></li>
102
- </ul>
103
- <!-- Tab panes -->
104
- <div class="tab-content outline">
105
- <%= render partial: 'bulkrax/shared/work_entries_tab', locals: { item: @exporter, entries: @work_entries } %>
106
- <%= render partial: 'bulkrax/shared/collection_entries_tab', locals: { item: @exporter, entries: @collection_entries } %>
107
- <%= render partial: 'bulkrax/shared/file_set_entries_tab', locals: { item: @exporter, entries: @file_set_entries } %>
100
+ <div class="outline">
101
+ <%= render partial: 'bulkrax/shared/entries_tab', locals: { item: @exporter } %>
108
102
  </div>
109
103
  <br>
110
104
  <%= link_to 'Edit', edit_exporter_path(@exporter) %>
@@ -3,10 +3,10 @@
3
3
  f = "#{form.lookup_action}_importer"
4
4
  f = "#{f}_#{@importer.id}" unless @importer.new_record?
5
5
  %>
6
- <div id='cloud-files'>
6
+ <div id='cloud-files'>
7
7
  <button type="button" data-toggle="browse-everything" data-route="<%=browse_everything_engine.root_path%>"
8
8
  data-target="#<%= f %>" class="btn btn-primary" id="browse">
9
- <span class="glyphicon glyphicon-plus"></span>
9
+ <span class="fa fa-plus"></span>
10
10
  Add Cloud Files
11
11
  </button>
12
12
  </div>
@@ -25,13 +25,19 @@
25
25
  <h4>Add CSV File to Import:</h4>
26
26
  <%# accept a single file upload; data files and bags will need to be added another way %>
27
27
 
28
- <%= fi.input :file_style, collection: ['Upload a File', 'Specify a Path on the Server'], as: :radio_buttons, label: false %>
28
+ <% file_style_list = ['Upload a File', 'Specify a Path on the Server'] %>
29
+ <% file_style_list << 'Existing Entries' unless importer.new_record? %>
30
+ <%= fi.input :file_style, collection: file_style_list, as: :radio_buttons, label: false %>
29
31
  <div id='file_upload'>
30
- <%= fi.input 'file', as: :file, input_html: { accept: 'text/csv,application/zip' } %><br />
32
+ <%= fi.input 'file', as: :file, input_html: { accept: 'text/csv,application/zip,application/gzip' } %><br />
31
33
  </div>
32
34
  <div id='file_path'>
33
35
  <%= fi.input :import_file_path, as: :string, input_html: { value: importer.parser_fields['import_file_path'] } %>
34
36
  </div>
37
+ <div id='existing_options'>
38
+ <%= fi.collection_check_boxes :entry_statuses, [['Failed'], ['Pending'], ['Skipped'], ['Deleted'], ['Complete']], :first, :first %>
39
+ </div>
40
+
35
41
  <% if defined?(::Hyrax) && Hyrax.config.browse_everything? %>
36
42
  <h4>Add Files to Import:</h4>
37
43
  <p>Choose files to upload. The filenames must be unique, and the filenames must be referenced in a column called 'file' in the accompanying CSV file.</p>
@@ -34,7 +34,14 @@
34
34
  <%= form.button :submit,
35
35
  value: 'Update and Replace Files',
36
36
  class: 'btn btn-primary',
37
- data: {confirm: "Are you sure? This will remove all files before adding them from the import."} %>
37
+ data: {confirm: "Are you sure? This will remove all files before adding them from the import."} %>
38
+ <hr />
39
+ <p>Remove all works and then run the import again from a clean slate. This will remove all files and associations and any edits made since the last import will be lost.</p>
40
+ <%= form.button :submit,
41
+ value: 'Remove and Rerun',
42
+ class: 'btn btn-primary',
43
+ data: {confirm: "Are you sure? This will delete all the works and any associated files and relationships before re running."} %>
44
+
38
45
  <% end %>
39
46
  <hr />
40
47
 
@@ -0,0 +1,18 @@
1
+ <div class="modal fade" id="bulkraxItemModal" tabindex="-1" role="dialog" aria-labelledby="bulkraxItemModalLabel">
2
+ <div class="modal-dialog" role="document">
3
+ <div class="modal-content">
4
+ <div class="modal-body">
5
+ <h5>Options for Updating an Entry</h5>
6
+ <hr />
7
+ <p>Rebuild metadata and files.</p>
8
+ <%= link_to 'Build', item_entry_path(item, e), method: :patch, class: 'btn btn-primary' %>
9
+ <hr />
10
+ <p>Remove existing work and then recreate the works metadata and files.</p>
11
+ <%= link_to 'Remove and then Build', item_entry_path(item, e, destroy_first: true), method: :patch, class: 'btn btn-primary' %>
12
+ </div>
13
+ <div class="modal-footer">
14
+ <button type="button" class="btn btn-default" data-dismiss="modal"><%= t('helpers.action.cancel') %></button>
15
+ </div>
16
+ </div>
17
+ </div>
18
+ </div>
@@ -15,7 +15,7 @@
15
15
  </button>
16
16
  <%= render 'edit_form_buttons', form: form %>
17
17
  <% cancel_path = form.object.persisted? ? importer_path(form.object) : importers_path %>
18
- | <%= link_to t('.cancel'), cancel_path, class: 'btn btn-default ' %>
18
+ | <%= link_to t('bulkrax.cancel'), cancel_path, class: 'btn btn-default ' %>
19
19
  </div>
20
20
  </div>
21
21
  <% end %>
@@ -13,69 +13,25 @@
13
13
 
14
14
  <div class="panel panel-default">
15
15
  <div class="panel-body">
16
- <% if @importers.present? %>
17
- <div class="table-responsive">
18
- <table class="table table-striped datatable">
19
- <thead>
20
- <tr>
21
- <th scope="col">Name</th>
22
- <th scope="col">Status</th>
23
- <th scope="col">Last Run</th>
24
- <th scope="col">Next Run</th>
25
- <th scope="col">Entries Enqueued</th>
26
- <th scope="col">Entries Processed</th>
27
- <th scope="col">Entries Failed</th>
28
- <th scope="col">Entries Deleted Upstream</th>
29
- <th scope="col">Total Collection Entries</th>
30
- <th scope="col">Total Work Entries</th>
31
- <th scope="col">Total File Set Entries</th>
32
- <th scope="col"></th>
33
- <th scope="col"></th>
34
- <th scope="col"></th>
35
- </tr>
36
- </thead>
37
- <tbody>
38
- <% @importers.each do |importer| %>
39
- <tr>
40
- <th scope="row"><%= link_to importer.name, importer_path(importer) %></th>
41
- <td><%= importer.status %></td>
42
- <td><%= importer.last_imported_at.strftime("%b %d, %Y") if importer.last_imported_at %></td>
43
- <td><%= importer.next_import_at.strftime("%b %d, %Y") if importer.next_import_at %></td>
44
- <td><%= importer.last_run&.enqueued_records %></td>
45
- <td><%= (importer.last_run&.processed_records || 0) %></td>
46
- <td><%= (importer.last_run&.failed_records || 0) %></td>
47
- <td><%= importer.last_run&.deleted_records %></td>
48
- <td><%= importer.last_run&.total_collection_entries %></td>
49
- <td><%= importer.last_run&.total_work_entries %></td>
50
- <td><%= importer.last_run&.total_file_set_entries %></td>
51
- <td><%= link_to raw('<span class="glyphicon glyphicon-info-sign"></span>'), importer_path(importer) %></td>
52
- <td><%= link_to raw('<span class="glyphicon glyphicon-pencil"></span>'), edit_importer_path(importer) %></td>
53
- <td><%= link_to raw('<span class="glyphicon glyphicon-remove"></span>'), importer, method: :delete, data: { confirm: 'Are you sure?' } %></td>
54
- </tr>
55
- <% end %>
56
- </tbody>
57
- </table>
58
- </div>
59
- <% else %>
60
- <p>No importers have been created.</p>
61
- <% end %>
16
+ <div class="table-responsive">
17
+ <table id='importers-table' class="table table-striped">
18
+ <thead>
19
+ <tr>
20
+ <th scope="col">Name</th>
21
+ <th scope="col">Status</th>
22
+ <th scope="col">Last Run</th>
23
+ <th scope="col">Next Run</th>
24
+ <th scope="col">Entries Enqueued</th>
25
+ <th scope="col">Entries Processed</th>
26
+ <th scope="col">Entries Failed</th>
27
+ <th scope="col">Entries Deleted Upstream</th>
28
+ <th scope="col">Total Collection Entries</th>
29
+ <th scope="col">Total Work Entries</th>
30
+ <th scope="col">Total File Set Entries</th>
31
+ <th scope="col">Actions</th>
32
+ </tr>
33
+ </thead>
34
+ </table>
35
+ </div>
62
36
  </div>
63
37
  </div>
64
-
65
- <script>
66
- $(function() {
67
- $('#DataTables_Table_0').DataTable({
68
- destroy: true, /* Reinitialize DataTable with config below */
69
- 'columnDefs': [
70
- { 'orderable': true, 'targets': [...Array(10).keys()] },
71
- { 'orderable': false, 'targets': [10, 11, 12] }
72
- ],
73
- 'language': {
74
- 'info': 'Showing _START_ to _END_ of _TOTAL_ importers',
75
- 'infoEmpty': 'No importers to show',
76
- 'infoFiltered': '(filtered from _MAX_ total importers)',
77
- 'lengthMenu': 'Show _MENU_ importers'
78
- }
79
- })
80
- })
81
- </script>
@@ -18,7 +18,7 @@
18
18
  <%= form.button :submit, value: 'Create', class: 'btn btn-primary' %>
19
19
  |
20
20
  <% cancel_path = form.object.persisted? ? importer_path(form.object) : importers_path %>
21
- <%= link_to t('.cancel'), cancel_path, class: 'btn btn-default ' %>
21
+ <%= link_to t('bulkrax.cancel'), cancel_path, class: 'btn btn-default ' %>
22
22
  </div>
23
23
  </div>
24
24
  <% end %>
@@ -1,9 +1,10 @@
1
1
  <div class="col-xs-12 main-header">
2
2
  <h1><span class="fa fa-cloud-upload" aria-hidden="true"></span> Importer: <%= @importer.name %></h1>
3
- <% if @importer.parser_klass == 'Bulkrax::CsvParser' && @work_entries.map(&:failed?).any? %>
3
+
4
+ <% if @importer.failed_entries? %>
4
5
  <div class="pull-right">
5
- <%= link_to 'Export Errored Entries', importer_export_errors_path(@importer.id), class: 'btn btn-primary' %>
6
- <%= link_to 'Upload Corrected Entries', importer_upload_corrected_entries_path(@importer.id), class: 'btn btn-primary' %>
6
+ <%= link_to 'Export Errored Entries', importer_export_errors_path(@importer.id), class: 'btn btn-primary', data: { turbolinks: false }%>
7
+ <%= link_to 'Upload Corrected Entries', importer_upload_corrected_entries_path(@importer.id), class: 'btn btn-primary' if @importer.parser.is_a?(Bulkrax::CsvParser) %>
7
8
  </div>
8
9
  <% end %>
9
10
  </div>
@@ -44,7 +45,7 @@
44
45
  Parser fields:
45
46
  </a>
46
47
  <a role="button" data-toggle="collapse" data-target="#parser-fields-importer-show" aria-expanded="true" aria-controls="parser-fields-importer-show">
47
- <div class="accordion-icon glyphicon glyphicon-remove-circle" aria-hidden="true"></div>
48
+ <div class="accordion-icon fa fa-times-circle" aria-hidden="true"></div>
48
49
  </a>
49
50
  </div>
50
51
  <div id="parser-fields-importer-show" class="accordion-collapse collapse" role="tabpanel" aria-labelledby="parser-fields-heading">
@@ -75,17 +76,10 @@
75
76
 
76
77
  <div class="bulkrax-nav-tab-bottom-margin">
77
78
  <!-- Nav tabs -->
78
- <ul class="bulkrax-nav-tab-top-margin tab-nav nav nav-tabs" role="tablist">
79
- <li role="presentation" class="nav-link active"><a href="#work-entries" aria-controls="work-entries" role="tab" data-toggle="tab"><%= t('bulkrax.importer.labels.work_entries') %></a></li>
80
- <li role="presentation" class="nav-link"><a href="#collection-entries" aria-controls="collection-entries" role="tab" data-toggle="tab"><%= t('bulkrax.importer.labels.collection_entries') %></a></li>
81
- <li role="presentation" class="nav-link"><a href="#file-set-entries" aria-controls="file-set-entries" role="tab" data-toggle="tab"><%= t('bulkrax.importer.labels.file_set_entries') %></a></li>
82
- </ul>
83
- <!-- Tab panes -->
84
- <div class="tab-content outline">
85
- <%= render partial: 'bulkrax/shared/work_entries_tab', locals: { item: @importer, entries: @work_entries } %>
86
- <%= render partial: 'bulkrax/shared/collection_entries_tab', locals: { item: @importer, entries: @collection_entries } %>
87
- <%= render partial: 'bulkrax/shared/file_set_entries_tab', locals: { item: @importer, entries: @file_set_entries } %>
79
+ <div class="outline">
80
+ <%= render partial: 'bulkrax/shared/entries_tab', locals: { item: @importer} %>
88
81
  </div>
82
+ <%= render partial: 'bulkrax/importers/edit_item_buttons', locals: { item: @importer, e: @first_entry } if @first_entry.present? %>
89
83
  </div>
90
84
 
91
85
  <p class="bulkrax-p-align">
@@ -7,7 +7,7 @@
7
7
  <p>
8
8
  Upload <b>only</b> the corrected entries for the <b><%= @importer.name %></b> importer. To export failed entries for correction,
9
9
  <%= link_to importer_export_errors_path(@importer.id) do %>
10
- click here <span class='glyphicon glyphicon-download-alt'></span>
10
+ click here <span class='fa fa-download'></span>
11
11
  <% end %>
12
12
  </p>
13
13
  <p>Only CSV files are allowed.</p>
@@ -18,7 +18,7 @@
18
18
  <div class='fileupload-buttonbar hide-required-tag'>
19
19
  <%= fi.input 'file',
20
20
  as: :file,
21
- label: "<span class='glyphicon glyphicon-plus'></span><span> Add file...</span>".html_safe,
21
+ label: "<span class='fa fa-plus'></span><span> Add file...</span>".html_safe,
22
22
  label_html: {
23
23
  class: 'btn btn-success'
24
24
  },
@@ -5,7 +5,7 @@
5
5
  Errors:
6
6
  </a>
7
7
  <a role="button" data-toggle="collapse" data-target="#error-trace-show" aria-expanded="true" aria-controls="error-trace-show">
8
- <div class="accordion-icon glyphicon glyphicon-remove-circle" aria-hidden="true"></div>
8
+ <div class="accordion-icon fa fa-times-circle" aria-hidden="true"></div>
9
9
  </a>
10
10
  </div>
11
11
  <div id="error-trace-show" class="accordion-collapse collapse" role="tabpanel" aria-labelledby="error-trace-show">
@@ -5,7 +5,7 @@
5
5
  <strong>Field mapping:</strong>
6
6
  </a>
7
7
  <a role="button" data-toggle="collapse" data-target="#field-mapping-show" aria-expanded="true" aria-controls="field-mapping-show">
8
- <div class="accordion-icon glyphicon glyphicon-remove-circle" aria-hidden="true"></div>
8
+ <div class="accordion-icon fa fa-times-circle" aria-hidden="true"></div>
9
9
  </a>
10
10
  </div>
11
11
  <div id="field-mapping-show" class="accordion-collapse collapse" role="tabpanel" aria-labelledby="field-mapping-show">
@@ -0,0 +1,16 @@
1
+ <div class="tab-pane bulkrax-nav-tab-table-left-align" >
2
+ <table id='importer-show-table' class='table table-striped'>
3
+ <thead>
4
+ <tr>
5
+ <th><%= t('bulkrax.table_header.labels.identifier') %></th>
6
+ <th><%= t('bulkrax.table_header.labels.entry_id') %></th>
7
+ <th><%= t('bulkrax.table_header.labels.status') %></th>
8
+ <th><%= t('bulkrax.table_header.labels.type') %></th>
9
+ <th><%= t('bulkrax.table_header.labels.updated_at') %></th>
10
+ <th><%= t('bulkrax.table_header.labels.errors') %></th>
11
+ <th><%= t('bulkrax.table_header.labels.actions') %></th>
12
+ </tr>
13
+ </thead>
14
+ </table>
15
+ <div id='importer-entry-classes' class='hidden'><%= [item.parser.entry_class.to_s, item.parser.collection_entry_class.to_s, item.parser.file_set_entry_class.to_s].compact.join('|') %></div>
16
+ </div>
@@ -1,9 +1,16 @@
1
1
  en:
2
+ helpers:
3
+ action:
4
+ importer:
5
+ new: "New"
6
+ exporter:
7
+ new: "New"
2
8
  bulkrax:
3
9
  admin:
4
10
  sidebar:
5
11
  exporters: Exporters
6
12
  importers: Importers
13
+ cancel: "Cancel"
7
14
  exporter:
8
15
  labels:
9
16
  all: All
data/config/routes.rb CHANGED
@@ -3,15 +3,21 @@
3
3
  Bulkrax::Engine.routes.draw do
4
4
  resources :exporters do
5
5
  get :download
6
- resources :entries, only: %i[show]
6
+ get :entry_table
7
+ collection do
8
+ get :exporter_table
9
+ end
10
+ resources :entries, only: %i[show update destroy]
7
11
  end
8
12
  resources :importers do
9
13
  put :continue
14
+ get :entry_table
10
15
  get :export_errors
11
16
  collection do
17
+ get :importer_table
12
18
  post :external_sets
13
19
  end
14
- resources :entries, only: %i[show]
20
+ resources :entries, only: %i[show update destroy]
15
21
  get :upload_corrected_entries
16
22
  post :upload_corrected_entries_file
17
23
  end
@@ -1,14 +1,25 @@
1
+ # This migration comes from bulkrax (originally 20230608153601)
1
2
  class AddIndicesToBulkrax < ActiveRecord::Migration[5.1]
2
3
  def change
3
- add_index :bulkrax_entries, :identifier unless index_exists?(:bulkrax_entries, :identifier)
4
- add_index :bulkrax_entries, :type unless index_exists?(:bulkrax_entries, :type)
5
- add_index :bulkrax_entries, [:importerexporter_id, :importerexporter_type], name: 'bulkrax_entries_importerexporter_idx' unless index_exists?(:bulkrax_entries, [:importerexporter_id, :importerexporter_type], name: 'bulkrax_entries_importerexporter_idx')
6
-
7
- add_index :bulkrax_pending_relationships, :parent_id unless index_exists?(:bulkrax_pending_relationships, :parent_id)
8
- add_index :bulkrax_pending_relationships, :child_id unless index_exists?(:bulkrax_pending_relationships, :child_id)
4
+ check_and_add_index :bulkrax_entries, :identifier
5
+ check_and_add_index :bulkrax_entries, :type
6
+ check_and_add_index :bulkrax_entries, [:importerexporter_id, :importerexporter_type], name: 'bulkrax_entries_importerexporter_idx'
7
+ check_and_add_index :bulkrax_pending_relationships, :parent_id
8
+ check_and_add_index :bulkrax_pending_relationships, :child_id
9
+ check_and_add_index :bulkrax_statuses, [:statusable_id, :statusable_type], name: 'bulkrax_statuses_statusable_idx'
10
+ check_and_add_index :bulkrax_statuses, [:runnable_id, :runnable_type], name: 'bulkrax_statuses_runnable_idx'
11
+ check_and_add_index :bulkrax_statuses, :error_class
12
+ end
9
13
 
10
- add_index :bulkrax_statuses, [:statusable_id, :statusable_type], name: 'bulkrax_statuses_statusable_idx' unless index_exists?(:bulkrax_statuses, [:statusable_id, :statusable_type], name: 'bulkrax_statuses_statusable_idx')
11
- add_index :bulkrax_statuses, [:runnable_id, :runnable_type], name: 'bulkrax_statuses_runnable_idx' unless index_exists?(:bulkrax_statuses, [:runnable_id, :runnable_type], name: 'bulkrax_statuses_runnable_idx')
12
- add_index :bulkrax_statuses, :error_class unless index_exists?(:bulkrax_statuses, :error_class)
14
+ if RUBY_VERSION =~ /^2/
15
+ def check_and_add_index(table_name, column_name, options = {})
16
+ add_index(table_name, column_name, options) unless index_exists?(table_name, column_name, options)
17
+ end
18
+ elsif RUBY_VERSION =~ /^3/
19
+ def check_and_add_index(table_name, column_name, **options)
20
+ add_index(table_name, column_name, **options) unless index_exists?(table_name, column_name, **options)
21
+ end
22
+ else
23
+ raise "Ruby version #{RUBY_VERSION} is unknown"
13
24
  end
14
25
  end
@@ -0,0 +1,7 @@
1
+ class DenormalizeStatusMessage < ActiveRecord::Migration[5.2]
2
+ def change
3
+ add_column :bulkrax_entries, :status_message, :string, default: 'Pending' unless column_exists?(:bulkrax_entries, :status_message)
4
+ add_column :bulkrax_importers, :status_message, :string, default: 'Pending' unless column_exists?(:bulkrax_importers, :status_message)
5
+ add_column :bulkrax_exporters, :status_message, :string, default: 'Pending' unless column_exists?(:bulkrax_exporters, :status_message)
6
+ end
7
+ end
@@ -0,0 +1,6 @@
1
+ class UpdateIdentifierIndex < ActiveRecord::Migration[5.2]
2
+ def change
3
+ remove_index :bulkrax_entries, :identifier if index_exists?(:bulkrax_entries, :identifier )
4
+ add_index :bulkrax_entries, [:identifier, :importerexporter_id, :importerexporter_type], name: 'bulkrax_identifier_idx' unless index_exists?(:bulkrax_entries, [:identifier, :importerexporter_id, :importerexporter_type], name: 'bulkrax_identifier_idx')
5
+ end
6
+ end