Bug 10558 - Convert records table in manage-marc-import.pl to Ajax DataTable

Some libraries would like to sort by columns for the records of an
import batch. This seems like a good use of Ajax DataTables.

Test plan:
1) Apply this patch
2) Import a record batch into Koha
   a) Use some form of matching
   b) Have some records that will match and some that won't
   c) Have at least 30 records so you can test the pager
3) Verify the new table is functionally equivalent to the old static one

Signed-off-by: Owen Leonard <oleonard@myacpl.org>

Tests fine and looks good with the exception of the corrections I put in
a follow-up.

Signed-off-by: Galen Charlton <gmc@esilibrary.com>
This commit is contained in:
Kyle Hall 2013-07-09 12:30:58 -04:00 committed by Galen Charlton
parent 15ad3061b2
commit 4d32421634
4 changed files with 249 additions and 161 deletions

View file

@ -1028,9 +1028,15 @@ starting at the given offset.
=cut
sub GetImportRecordsRange {
my ($batch_id, $offset, $results_per_group, $status) = @_;
my ( $batch_id, $offset, $results_per_group, $status, $parameters ) = @_;
my $dbh = C4::Context->dbh;
my $order_by =
$dbh->quote_identifier( $parameters->{order_by} || 'import_record_id' );
my $order_by_direction =
uc( $parameters->{order_by_direction} ) eq 'DESC' ? 'DESC' : 'ASC';
my $query = "SELECT title, author, isbn, issn, authorized_heading, import_records.import_record_id,
record_sequence, status, overlay_status,
matched_biblionumber, matched_authid, record_type
@ -1044,7 +1050,8 @@ sub GetImportRecordsRange {
$query .= " AND status=?";
push(@params,$status);
}
$query.=" ORDER BY import_record_id";
$query.=" ORDER BY $order_by $order_by_direction";
if($results_per_group){
$query .= " LIMIT ?";

View file

@ -1,38 +1,16 @@
[% BLOCK final_match_link %]
[% IF ( record.record_type == 'biblio' ) %]
<a target="_blank" href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% record.final_match_id %]">[% record.final_match_id %]</a>
[% ELSIF ( record.record_type == 'auth' ) %]
<a href="/cgi-bin/koha/authorities/detail.pl?authid=[% record.final_match_id %]">[% record.final_match_id %]</a>
[% END %]
[% END %]
[% BLOCK match_link %]
[% IF ( record_lis.match_id ) %]
<tr>
<td />
[% IF ( record.record_type == 'biblio' ) %]
<td class="highlight" colspan="4">Matches biblio [% record_lis.match_id %] (score = [% record_lis.match_score %]): <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% record_lis.match_id %]">[% record_lis.match_citation %]</a></td>
[% ELSIF ( record.record_type == 'auth' ) %]
<td class="highlight" colspan="4">Matches authority [% record_lis.match_id %] (score = [% record_lis.match_score %]): <a href="/cgi-bin/koha/authorities/detail.pl?authid=[% record_lis.match_id %]">[% record_lis.match_citation %]</a> |
<a href="/cgi-bin/koha/authorities/merge.pl?mergereference=breeding&authid=[% record_lis.match_id %]&authid=[% record_lis.import_record_id %]">Merge</a>
</td>
[% END %]
</tr>
[% ELSIF ( record.record_type == 'auth') %]
<tr data-authid="[% record_lis.import_record_id %]">
<td />
<td class="highlight" colspan="4"><a href="#" class="merge_auth">Search for a record to merge in a new window</a></td>
</tr>
[% END %]
[% END %]
[% INCLUDE 'doc-head-open.inc' %]
<title>Koha &rsaquo; Tools &rsaquo; Manage staged MARC records
[% IF ( import_batch_id ) %]
&rsaquo; Batch [% import_batch_id %]
[% END %]
</title>
[% INCLUDE 'greybox.inc' %]
[% INCLUDE 'doc-head-close.inc' %]
<script type="text/javascript" src="[% themelang %]/js/background-job-progressbar.js"></script>
<link rel="stylesheet" type="text/css" href="[% themelang %]/css/datatables.css" />
<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.dataTables.min.js"></script>
<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.dataTables.columnFilter.js"></script>
[% INCLUDE 'datatables-strings.inc' %]
<script type="text/javascript" src="[% themelang %]/js/datatables.js"></script>
<script type="text/JavaScript" language="JavaScript">
//<![CDATA[
var MSG_CONFIRM_CLEAN = _("Clear all reservoir records staged in this batch? This cannot be undone.");
@ -49,13 +27,71 @@ $(document).ready(function(){
$(this).parent().hide();
});
$('.merge_auth').click(function(event) {
event.preventDefault();
var authid = $(this).parents('tr').attr('data-authid');
$.cookie('auth_to_merge', JSON.stringify({ 'authid': authid, 'summary': $('tr[data-id="' + authid + '"] .citation').text(), 'mergereference': 'breeding' }), { 'path': '/' });
window.open("/cgi-bin/koha/authorities/authorities-home.pl");
$("#records-table").dataTable({
"aLengthMenu": [[10, 15, 20, 25, 50, 100], [10, 15, 20, 25, 50, 100]],
"iDisplayLength" : 20,
"bAutoWidth": false,
"bFilter": false,
"bProcessing": true,
"bServerSide": true,
"sAjaxSource": 'batch_records_ajax.pl',
"sPaginationType": "full_numbers",
"aoColumns": [
{ "mDataProp": "import_record_id" },
{ "mDataProp": "citation" },
{ "mDataProp": "status" },
{ "mDataProp": "overlay_status" },
{ "mDataProp": "match_citation" },
{ "mDataProp": "matched" },
],
"fnServerData": function ( sSource, aoData, fnCallback ) {
aoData.push( { "name": "import_batch_id", "value": [% import_batch_id %] } );
$.getJSON( sSource, aoData, function (json) {
fnCallback(json)
} );
},
"fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
$('td:eq(1)', nRow).html(
'<a href="javascript:void()" onclick="show_marc('
+ aData['import_record_id']
+ ')">' + aData['citation'] + '</a>'
);
if ( aData['match_id'] ) {
$('td:eq(4)', nRow).html(
_("Matches biblio ")
+ aData['match_id']
+ " (" + _("score") + "="
+ aData['score']
+ '):' + '<a target="_blank" href="http://staff.kohadev/cgi-bin/koha/catalogue/detail.pl?biblionumber='
+ aData['match_id'] + '">' + aData['match_citation'] + '</a>'
);
}
$('td:eq(5)', nRow).html(
'<a target="_blank" href="http://staff.kohadev/cgi-bin/koha/catalogue/detail.pl?biblionumber='
+ aData['matched'] + '">' + aData['matched'] + '</a>'
);
},
});
});
function show_marc( id ) {
var page = "/cgi-bin/koha/catalogue/showmarc.pl?importid=" + id;
var $dialog = $('<div></div>')
.html('<iframe style="border: 0px; " src="' + page + '" width="100%" height="100%"></iframe>')
.dialog({
autoOpen: false,
modal: true,
height: 625,
width: 500,
title: _("MARC Preview")
});
$dialog.dialog('open');
}
//]]>
</script>
<style type="text/css">
@ -375,85 +411,18 @@ Page
[% END %]
[% END %]
[% IF ( record_list ) %]
[% IF ( pages ) %]
<div class="pages">
Page
[% FOREACH page IN pages %]
[% IF ( page.current_page ) %]
<span class="current">[% page.page_number %]</span>
[% ELSE %]
<a class="nav" href="[% page.script_name %]?import_batch_id=[% import_batch_id %]&amp;offset=[% page.offset %]">[% page.page_number %]</a>
[% END %]
[% END %]
</div>
[% END %]
<table>
<tr>
<th>#</th>
<th>Citation</th>
<th>Status</th>
<th>Match?</th>
<th>Record</th>
</tr>
[% FOREACH record_lis IN record_list %]
[% UNLESS ( loop.odd ) %]<tr data-id="[% record_lis.import_record_id %]" class="highlight">[% ELSE %]<tr data-id="[% record_lis.import_record_id %]">[% END %]
<td>[% record_lis.record_sequence %]</td>
<td><a class="citation" href="/cgi-bin/koha/catalogue/showmarc.pl?importid=[% record_lis.import_record_id %]" rel="gb_page_center[600,500]">[% record_lis.citation %]</a></td>
<td>
[% IF ( record_lis.status == 'imported' ) %]
Imported
[% ELSIF ( record_lis.status == 'ignored' ) %]
Ignored
[% ELSIF ( record_lis.status == 'reverted' ) %]
Reverted
[% ELSIF ( record_lis.status == 'staged' ) %]
Staged
[% ELSIF ( record_lis.status == 'error' ) %]
Error
[% ELSE %]
[% record_lis.status %]
[% END %]
</td>
<td>
[% IF ( record_lis.overlay_status == 'no_match' ) %]
No match
[% ELSIF ( record_lis.overlay_status == 'match_applied' ) %]
Match applied
[% ELSIF ( record_lis.overlay_status == 'auto_match' ) %]
Match found
[% ELSE %]
[% record_lis.overlay_status %]
[% END %]
</td>
<td>[% IF ( record_lis.final_match_id ) %]
[% PROCESS final_match_link record=record_lis %]
[% END %]
</td>
</tr>
[% PROCESS match_link record=record_lis %]
[% END %]
<table id="records-table">
<thead>
<tr>
<th>#</th>
<th>Citation</th>
<th>Status</th>
<th>Match?</th>
<th>&nbsp;</th>
<th>Record</th>
</tr>
</thead>
</table>
[% IF ( pages ) %]
<div class="pages">
Page
[% FOREACH page IN pages %]
[% IF ( page.current_page ) %]
<span class="current">[% page.page_number %]</span>
[% ELSE %]
<a class="nav" href="[% page.script_name %]?import_batch_id=[% import_batch_id %]&amp;offset=[% page.offset %]">[% page.page_number %]</a>
[% END %]
[% END %]
</div>
[% END %]
[% ELSE %]
[% IF ( batch_info ) %]
<div class="dialog alert">There are no records in this batch to import.
<a href="/cgi-bin/koha/tools/manage-marc-import.pl">Manage staged MARC records</a>.</div>
[% END %]
[% END %]
</div>
</div>

112
tools/batch_records_ajax.pl Executable file
View file

@ -0,0 +1,112 @@
#!/usr/bin/perl
# This software is placed under the gnu General Public License, v2 (http://www.gnu.org/licenses/gpl.html)
# Copyright 2007 Tamil s.a.r.l.
#
# This file is part of Koha.
#
# Koha is free software; you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with Koha; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
=head1 ysearch.pl
=cut
use Modern::Perl;
use CGI;
use JSON qw/ to_json /;
use C4::Context;
use C4::Charset;
use C4::Auth qw/check_cookie_auth/;
use C4::ImportBatch;
my $input = new CGI;
my @sort_columns =
qw/import_record_id title status overlay_status overlay_status/;
my $import_batch_id = $input->param('import_batch_id');
my $offset = $input->param('iDisplayStart');
my $results_per_page = $input->param('iDisplayLength');
my $sorting_column = $sort_columns[ $input->param('iSortCol_0') ];
my $sorting_direction = $input->param('sSortDir_0');
binmode STDOUT, ":encoding(UTF-8)";
print $input->header( -type => 'text/plain', -charset => 'UTF-8' );
my ( $auth_status, $sessionID ) =
check_cookie_auth( $input->cookie('CGISESSID'), { editcatalogue => '*' } );
if ( $auth_status ne "ok" ) {
exit 0;
}
my $batch = GetImportBatch($import_batch_id);
my $records =
GetImportRecordsRange( $import_batch_id, $offset, $results_per_page, undef,
{ order_by => $sorting_column, order_by_direction => $sorting_direction } );
my @list = ();
foreach my $record (@$records) {
my $citation = $record->{'title'} || $record->{'authorized_heading'};
$citation .= " $record->{'author'}" if $record->{'author'};
$citation .= " (" if $record->{'issn'} or $record->{'isbn'};
$citation .= $record->{'isbn'} if $record->{'isbn'};
$citation .= ", " if $record->{'issn'} and $record->{'isbn'};
$citation .= $record->{'issn'} if $record->{'issn'};
$citation .= ")" if $record->{'issn'} or $record->{'isbn'};
my $match = GetImportRecordMatches( $record->{'import_record_id'}, 1 );
my $match_citation = '';
my $match_id;
if ( $#$match > -1 ) {
if ( $match->[0]->{'record_type'} eq 'biblio' ) {
$match_citation .= $match->[0]->{'title'}
if defined( $match->[0]->{'title'} );
$match_citation .= ' ' . $match->[0]->{'author'}
if defined( $match->[0]->{'author'} );
$match_id = $match->[0]->{'biblionumber'};
}
elsif ( $match->[0]->{'record_type'} eq 'auth' ) {
if ( defined( $match->[0]->{'authorized_heading'} ) ) {
$match_citation .= $match->[0]->{'authorized_heading'};
$match_id = $match->[0]->{'candidate_match_id'};
}
}
}
push @list,
{
DT_RowId => $record->{'import_record_id'},
import_record_id => $record->{'import_record_id'},
citation => $citation,
status => $record->{'status'},
overlay_status => $record->{'overlay_status'},
match_citation => $match_citation,
matched => $record->{'matched_biblionumber'}
|| $record->{'matched_authid'}
|| q{},
score => $#$match > -1 ? $match->[0]->{'score'} : 0,
match_id => $match_id,
};
}
my $data;
$data->{'iTotalRecords'} = $batch->{'num_records'};
$data->{'iTotalDisplayRecords'} = $batch->{'num_records'};
$data->{'sEcho'} = $input->param('sEcho') || undef;
$data->{'aaData'} = \@list;
print to_json($data);

View file

@ -352,55 +352,55 @@ sub import_records_list {
my ($template, $import_batch_id, $offset, $results_per_page) = @_;
my $batch = GetImportBatch($import_batch_id);
my $records = GetImportRecordsRange($import_batch_id, $offset, $results_per_page);
my @list = ();
foreach my $record (@$records) {
my $citation = $record->{'title'} || $record->{'authorized_heading'};
$citation .= " $record->{'author'}" if $record->{'author'};
$citation .= " (" if $record->{'issn'} or $record->{'isbn'};
$citation .= $record->{'isbn'} if $record->{'isbn'};
$citation .= ", " if $record->{'issn'} and $record->{'isbn'};
$citation .= $record->{'issn'} if $record->{'issn'};
$citation .= ")" if $record->{'issn'} or $record->{'isbn'};
my $match = GetImportRecordMatches($record->{'import_record_id'}, 1);
my $match_citation = '';
my $match_id;
if ($#$match > -1) {
if ($match->[0]->{'record_type'} eq 'biblio') {
$match_citation .= $match->[0]->{'title'} if defined($match->[0]->{'title'});
$match_citation .= ' ' . $match->[0]->{'author'} if defined($match->[0]->{'author'});
$match_id = $match->[0]->{'biblionumber'};
} elsif ($match->[0]->{'record_type'} eq 'auth') {
if (defined($match->[0]->{'authorized_heading'})) {
$match_citation .= $match->[0]->{'authorized_heading'};
$match_id = $match->[0]->{'candidate_match_id'};
}
}
}
push @list,
{ import_record_id => $record->{'import_record_id'},
final_match_id => $record->{'matched_biblionumber'} || $record->{'matched_authid'},
citation => $citation,
status => $record->{'status'},
record_sequence => $record->{'record_sequence'},
overlay_status => $record->{'overlay_status'},
# Sorry about the match_id being from the "biblionumber" field;
# as it turns out, any match id will go in biblionumber
match_id => $match_id,
match_citation => $match_citation,
match_score => $#$match > -1 ? $match->[0]->{'score'} : 0,
record_type => $record->{'record_type'},
};
}
my $num_records = $batch->{'num_records'};
$template->param(record_list => \@list);
add_page_numbers($template, $offset, $results_per_page, $num_records);
$template->param(offset => $offset);
$template->param(range_top => $offset + $results_per_page - 1);
$template->param(num_results => $num_records);
$template->param(results_per_page => $results_per_page);
# my $records = GetImportRecordsRange($import_batch_id);
# my @list = ();
# foreach my $record (@$records) {
# my $citation = $record->{'title'} || $record->{'authorized_heading'};
# $citation .= " $record->{'author'}" if $record->{'author'};
# $citation .= " (" if $record->{'issn'} or $record->{'isbn'};
# $citation .= $record->{'isbn'} if $record->{'isbn'};
# $citation .= ", " if $record->{'issn'} and $record->{'isbn'};
# $citation .= $record->{'issn'} if $record->{'issn'};
# $citation .= ")" if $record->{'issn'} or $record->{'isbn'};
#
# my $match = GetImportRecordMatches($record->{'import_record_id'}, 1);
# my $match_citation = '';
# my $match_id;
# if ($#$match > -1) {
# if ($match->[0]->{'record_type'} eq 'biblio') {
# $match_citation .= $match->[0]->{'title'} if defined($match->[0]->{'title'});
# $match_citation .= ' ' . $match->[0]->{'author'} if defined($match->[0]->{'author'});
# $match_id = $match->[0]->{'biblionumber'};
# } elsif ($match->[0]->{'record_type'} eq 'auth') {
# if (defined($match->[0]->{'authorized_heading'})) {
# $match_citation .= $match->[0]->{'authorized_heading'};
# $match_id = $match->[0]->{'candidate_match_id'};
# }
# }
# }
#
# push @list,
# { import_record_id => $record->{'import_record_id'},
# final_match_id => $record->{'matched_biblionumber'} || $record->{'matched_authid'},
# citation => $citation,
# status => $record->{'status'},
# record_sequence => $record->{'record_sequence'},
# overlay_status => $record->{'overlay_status'},
# # Sorry about the match_id being from the "biblionumber" field;
# # as it turns out, any match id will go in biblionumber
# match_id => $match_id,
# match_citation => $match_citation,
# match_score => $#$match > -1 ? $match->[0]->{'score'} : 0,
# record_type => $record->{'record_type'},
# };
# }
# my $num_records = $batch->{'num_records'};
# $template->param(record_list => \@list);
# add_page_numbers($template, $offset, $results_per_page, $num_records);
# $template->param(offset => $offset);
# $template->param(range_top => $offset + $results_per_page - 1);
# $template->param(num_results => $num_records);
# $template->param(results_per_page => $results_per_page);
$template->param(import_batch_id => $import_batch_id);
my $overlay_action = GetImportBatchOverlayAction($import_batch_id);
$template->param("overlay_action_${overlay_action}" => 1);