Skip to content

Commit

Permalink
Merge branch 'main' into hyrax-4-valkyrie-support
Browse files Browse the repository at this point in the history
* main:
  ♻️ Favor member_ids_ssim over file_set_ids_ssim (#929)
  🐛 Fix exporter page for Bootstrap 3 applications (#928)
  ♻️ Favor configuration over hard-coding (#927)
  Fix exporters show page - 2 (#926)
  Redo records with the remove_and_rerun property in the data, move individual remove and rerun to a background job (#923)
  Mark records as skipped if we do not see them during an import run (#922)
  For every importer / record combo there should be exactly one entry (#921)
  Add Skip to the datatabels (#920)
  Update Importer Index and Show Entries With Search, Filtering, Sort and More (#914)
  Restore rails5 support (#919)
  Strip out all special characters from csv headers (#918)
  Need to Include dry/monads in sample app to get generators working (#917)
  Found another place we need to include the monad lib. This time so that generators work
  Denormalize Status Message to that Entry Look Up Can Be Fast (#913)
  • Loading branch information
jeremyf committed Feb 23, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
2 parents 22eb48e + 4c68fbb commit 6d5517d
Showing 52 changed files with 1,038 additions and 405 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -40,7 +40,7 @@ jobs:
run: bundle exec rake db:migrate db:test:prepare

- name: Run rspec
run: bundle exec rake
run: bundle exec rake spec

- name: Upload coverage results
uses: actions/upload-artifact@v2
14 changes: 7 additions & 7 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -25,18 +25,18 @@ require 'bundler/gem_tasks'

require 'solr_wrapper/rake_task' unless Rails.env.production?

require 'rubocop/rake_task'

RuboCop::RakeTask.new(:rubocop) do |t|
t.options = ['--display-cop-names', '--ignore-parent-exclusion', '-a']
end

begin
require 'rspec/core/rake_task'

RSpec::Core::RakeTask.new(:spec)

task default: :spec
task default: [:rubocop, :spec]
rescue LoadError # rubocop:disable Lint/HandleExceptions
# no rspec available
end

require 'rubocop/rake_task'

RuboCop::RakeTask.new(:rubocop) do |t|
t.options = ['--display-cop-names']
end
139 changes: 139 additions & 0 deletions app/assets/javascripts/bulkrax/datatables.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
Blacklight.onLoad(function() {
if($('#importer-show-table').length) {
$('#importer-show-table').DataTable( {
'processing': true,
'serverSide': true,
"ajax": window.location.href.replace(/(\/(importers|exporters)\/\d+)/, "$1/entry_table.json"),
"pageLength": 30,
"lengthMenu": [[30, 100, 200], [30, 100, 200]],
"columns": [
{ "data": "identifier" },
{ "data": "id" },
{ "data": "status_message" },
{ "data": "type" },
{ "data": "updated_at" },
{ "data": "errors", "orderable": false },
{ "data": "actions", "orderable": false }
],
initComplete: function () {
// Add entry class filter
entrySelect.bind(this)()
// Add status filter
statusSelect.bind(this)()
// Add refresh link
refreshLink.bind(this)()
}
} );
}

if($('#importers-table').length) {
$('#importers-table').DataTable( {
'processing': true,
'serverSide': true,
"ajax": window.location.href.replace(/(\/importers)/, "$1/importer_table.json"),
"pageLength": 30,
"lengthMenu": [[30, 100, 200], [30, 100, 200]],
"columns": [
{ "data": "name" },
{ "data": "status_message" },
{ "data": "last_imported_at" },
{ "data": "next_import_at" },
{ "data": "enqueued_records", "orderable": false },
{ "data": "processed_records", "orderable": false },
{ "data": "failed_records", "orderable": false },
{ "data": "deleted_records", "orderable": false },
{ "data": "total_collection_entries", "orderable": false },
{ "data": "total_work_entries", "orderable": false },
{ "data": "total_file_set_entries", "orderable": false },
{ "data": "actions", "orderable": false }
],
initComplete: function () {
// Add status filter
statusSelect.bind(this)()
// Add refresh link
refreshLink.bind(this)()
}
} );
}

if($('#exporters-table').length) {
$('#exporters-table').DataTable( {
'processing': true,
'serverSide': true,
"ajax": window.location.href.replace(/(\/exporters)/, "$1/exporter_table.json"),
"pageLength": 30,
"lengthMenu": [[30, 100, 200], [30, 100, 200]],
"columns": [
{ "data": "name" },
{ "data": "status_message" },
{ "data": "created_at" },
{ "data": "download" },
{ "data": "actions", "orderable": false }
],
initComplete: function () {
// Add status filter
statusSelect.bind(this)()
// Add refresh link
refreshLink.bind(this)()
}
} );
}

})

function entrySelect() {
let entrySelect = document.createElement('select')
entrySelect.id = 'entry-filter'
entrySelect.classList.value = 'form-control input-sm'
entrySelect.style.marginRight = '10px'

entrySelect.add(new Option('Filter by Entry Class', ''))
// Read the options from the footer and add them to the entrySelect
$('#importer-entry-classes').text().split('|').forEach(function (col, i) {
entrySelect.add(new Option(col.trim()))
})
document.querySelector('div#importer-show-table_filter').firstChild.prepend(entrySelect)

// Apply listener for user change in value
entrySelect.addEventListener('change', function () {
var val = entrySelect.value;
this.api()
.search(val ? val : '', false, false)
.draw();
}.bind(this));
}

function statusSelect() {
let statusSelect = document.createElement('select');
statusSelect.id = 'status-filter'
statusSelect.classList.value = 'form-control input-sm'
statusSelect.style.marginRight = '10px'

statusSelect.add(new Option('Filter by Status', ''));
statusSelect.add(new Option('Complete'))
statusSelect.add(new Option('Pending'))
statusSelect.add(new Option('Failed'))
statusSelect.add(new Option('Skipped'))
statusSelect.add(new Option('Deleted'))
statusSelect.add(new Option('Complete (with failures)'))

document.querySelector('div.dataTables_filter').firstChild.prepend(statusSelect)

// Apply listener for user change in value
statusSelect.addEventListener('change', function () {
var val = statusSelect.value;
this.api()
.search(val ? val : '', false, false)
.draw();
}.bind(this));
}

function refreshLink() {
let refreshLink = document.createElement('a');
refreshLink.onclick = function() {
this.api().ajax.reload(null, false)
}.bind(this)
refreshLink.classList.value = 'glyphicon glyphicon-refresh'
refreshLink.style.marginLeft = '10px'
document.querySelector('div.dataTables_filter').firstChild.append(refreshLink)
}
8 changes: 4 additions & 4 deletions app/assets/javascripts/bulkrax/exporters.js
Original file line number Diff line number Diff line change
@@ -26,14 +26,14 @@ function removeRequired(allSources) {

// hide all export_source
function hide(allSources) {
allSources.addClass('d-none');
allSources.find('#exporter_export_source').addClass('.d-none').attr('type', 'd-none');
allSources.addClass('d-none hidden');
allSources.find('#exporter_export_source').addClass('.d-none hidden').attr('type', 'd-none hidden');
}

// unhide selected export_source
function unhideSelected(selectedSource) {
selectedSource.removeClass('d-none').removeAttr('type');
selectedSource.parent().removeClass('d-none').removeAttr('type');
selectedSource.removeClass('d-none hidden').removeAttr('type');
selectedSource.parent().removeClass('d-none hidden').removeAttr('type');
};

// add the autocomplete javascript
16 changes: 15 additions & 1 deletion app/assets/javascripts/bulkrax/importers.js.erb
Original file line number Diff line number Diff line change
@@ -74,12 +74,14 @@ function handleFileToggle(file_path) {
$('#file_path').hide()
$('#file_upload').hide()
$('#cloud').hide()
$('#existing_options').hide()
$('#file_path input').attr('required', null)
$('#file_upload input').attr('required', null)
} else {
$('#file_path').show()
$('#file_upload').hide()
$('#cloud').hide()
$('#existing_options').hide()
$('#file_path input').attr('required', 'required')
$('#file_upload input').attr('required', null)
$('#importer_parser_fields_file_style_specify_a_path_on_the_server').attr('checked', true)
@@ -89,23 +91,35 @@ function handleFileToggle(file_path) {
$('#file_path').hide()
$('#file_upload').show()
$('#cloud').hide()
$('#existing_options').hide()
$('#file_path input').attr('required', null)
$('#file_upload input').attr('required', 'required')
})
$('#importer_parser_fields_file_style_specify_a_path_on_the_server').click(function(e){
$('#file_path').show()
$('#file_upload').hide()
$('#cloud').hide()
$('#existing_options').hide()
$('#file_path input').attr('required', 'required')
$('#file_upload input').attr('required', null)
})
$('#importer_parser_fields_file_style_add_cloud_file').click(function(e){
$('#file_path').hide()
$('#file_upload').hide()
$('#cloud').show()
$('#existing_options').hide()
$('#file_path input').attr('required', null)
$('#file_upload input').attr('required', null)
})
$('#importer_parser_fields_file_style_existing_entries').click(function(e){
$('#file_path').hide()
$('#file_upload').hide()
$('#cloud').hide()
$('#existing_options').show()
$('#file_path input').attr('required', null)
$('#file_upload input').attr('required', null)
})

}

function handleParserKlass() {
@@ -189,4 +203,4 @@ function setError(selector, error) {
selector.attr('disabled', true)
}

$(document).on({'ready': prepBulkrax, 'turbolinks:load': prepBulkrax})
$(document).on({'ready': prepBulkrax, 'turbolinks:load': prepBulkrax})
7 changes: 6 additions & 1 deletion app/assets/stylesheets/bulkrax/import_export.scss
Original file line number Diff line number Diff line change
@@ -34,4 +34,9 @@ div#s2id_exporter_export_source_collection {

.bulkrax-clear-toggles {
clear: both;
}
}

#existing_options .collection_check_boxes {
margin-left: 10px;
margin-right: 10px;
}
24 changes: 20 additions & 4 deletions app/controllers/bulkrax/entries_controller.rb
Original file line number Diff line number Diff line change
@@ -17,13 +17,29 @@ def show

def update
@entry = Entry.find(params[:id])
@entry.factory&.find&.destroy if params[:destroy_first]
@entry.build
@entry.save
type = case @entry.type.downcase
when /fileset/
'file_set'
when /collection/
'collection'
else
'work'
end
item = @entry.importerexporter
# do not run counters as it loads the whole parser
current_run = item.current_run(skip_counts: true)
@entry.set_status_info('Pending', current_run)
ScheduleRelationshipsJob.set(wait: 5.minutes).perform_later(importer_id: @entry.importer.id)

if params[:destroy_first]
"Bulkrax::DeleteAndImport#{type.camelize}Job".constantize.perform_later(@entry, current_run)
else
"Bulkrax::Import#{type.camelize}Job".constantize.perform_later(@entry.id, current_run.id)
end

entry_path = item.class.to_s.include?('Importer') ? bulkrax.importer_entry_path(item.id, @entry.id) : bulkrax.exporter_entry_path(item.id, @entry.id)

redirect_back fallback_location: entry_path, notice: "Entry update ran, new status is #{@entry.status}"
redirect_back fallback_location: entry_path, notice: "Entry #{@entry.id} update has been queued"
end

def destroy
24 changes: 19 additions & 5 deletions app/controllers/bulkrax/exporters_controller.rb
Original file line number Diff line number Diff line change
@@ -4,9 +4,10 @@ module Bulkrax
class ExportersController < ApplicationController
include Hyrax::ThemedLayoutController if defined?(::Hyrax)
include Bulkrax::DownloadBehavior
include Bulkrax::DatatablesBehavior
before_action :authenticate_user!
before_action :check_permissions
before_action :set_exporter, only: [:show, :edit, :update, :destroy]
before_action :set_exporter, only: [:show, :entry_table, :edit, :update, :destroy]
with_themed_layout 'dashboard' if defined?(::Hyrax)

# GET /exporters
@@ -17,16 +18,29 @@ def index
add_exporter_breadcrumbs if defined?(::Hyrax)
end

def exporter_table
@exporters = Exporter.order(table_order).page(table_page).per(table_per_page)
@exporters = @exporters.where(exporter_table_search) if exporter_table_search.present?
respond_to do |format|
format.json { render json: format_exporters(@exporters) }
end
end

# GET /exporters/1
def show
if defined?(::Hyrax)
add_exporter_breadcrumbs
add_breadcrumb @exporter.name
end
@first_entry = @exporter.entries.first
end

@work_entries = @exporter.entries.where(type: @exporter.parser.entry_class.to_s).page(params[:work_entries_page]).per(30)
@collection_entries = @exporter.entries.where(type: @exporter.parser.collection_entry_class.to_s).page(params[:collections_entries_page]).per(30)
@file_set_entries = @exporter.entries.where(type: @exporter.parser.file_set_entry_class.to_s).page(params[:file_set_entries_page]).per(30)
def entry_table
@entries = @exporter.entries.order(table_order).page(table_page).per(table_per_page)
@entries = @entries.where(entry_table_search) if entry_table_search.present?
respond_to do |format|
format.json { render json: format_entries(@entries, @exporter) }
end
end

# GET /exporters/new
@@ -100,7 +114,7 @@ def download

# Use callbacks to share common setup or constraints between actions.
def set_exporter
@exporter = Exporter.find(params[:id])
@exporter = Exporter.find(params[:id] || params[:exporter_id])
end

# Only allow a trusted parameters through.
Loading
Oops, something went wrong.

0 comments on commit 6d5517d

Please sign in to comment.