Bug 10558 - Convert records table in manage-marc-import.pl to Ajax DataTable
authorKyle M Hall <kyle@bywatersolutions.com>
Tue, 9 Jul 2013 16:30:58 +0000 (12:30 -0400)
committerGalen Charlton <gmc@esilibrary.com>
Mon, 10 Mar 2014 15:46:49 +0000 (15:46 +0000)
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>
C4/ImportBatch.pm
koha-tmpl/intranet-tmpl/prog/en/modules/tools/manage-marc-import.tt
tools/batch_records_ajax.pl [new file with mode: 0755]
tools/manage-marc-import.pl

index c045878..f320c7a 100644 (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 ?";
index e8384c1..c19a05b 100644 (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>
diff --git a/tools/batch_records_ajax.pl b/tools/batch_records_ajax.pl
new file mode 100755 (executable)
index 0000000..f4a1542
--- /dev/null
@@ -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);
index f1a6c83..86dc975 100755 (executable)
@@ -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);