Bug 10212: Columns configuration for tables
authorJonathan Druart <jonathan.druart@biblibre.com>
Mon, 7 Jul 2014 08:28:21 +0000 (10:28 +0200)
committerTomas Cohen Arazi <tomascohen@gmail.com>
Tue, 26 Aug 2014 12:28:03 +0000 (09:28 -0300)
This development introduces ColVis into Koha and provides a configuration
page for columns visibility.

ColVis is a plugin for DataTables. It allows to change the visibility of
the columns in the table.

* This development adds:
  - the js and css file for ColVis
  - a new DB table 'columns_settings'
  - a new template plugin 'ColumnsSettings'
  - a new package C4::Utils::DataTables::ColumnsSettings
  - a new admin page admin/columns_settings.pl

* How it works:
A yaml file is created (admin/columns_settings.yml) in order to take an
inventory of all tables where ColVis is implemented. This file is read
to create the list of modules, pages and tables in the configuration
page.
There are 3 possible keys in the yml:
 - is_hidden: default is 0
The column will be hidden.
 - cannot_be_toggled: default is 0.
ColVis will allow to hide/show the column.
 - cannot_be_modified: default is 0
Default values (in the yml) won't be modifiable.

When a user changes (or saves) the configuration for one module, all
columns are added to the DB table. The values in the DB get the upper hand
on the yaml values.

* Humm, strange?
It seems weird to have 2 storages for the same values. But I
think it will be easy to add an entry and maintain the yaml rather than
adding a new row (and new entry in updatedatabase script) in the DB.

* To go further: We can imagine that the configuration is saved for each
user (and not globally like it is made with this patch).

This patch cannot be tested as it, you need to apply the "POC" patch.

Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Katrin Fischer <Katrin.Fischer.83@web.de>
Passes all tests and QA script, more comments on last patch.

Signed-off-by: Tomas Cohen Arazi <tomascohen@gmail.com>
C4/Utils/DataTables/ColumnsSettings.pm [new file with mode: 0644]
Koha/Template/Plugin/ColumnsSettings.pm [new file with mode: 0644]
admin/columns_settings.pl [new file with mode: 0755]
admin/columns_settings.yml [new file with mode: 0644]
koha-tmpl/intranet-tmpl/prog/en/includes/admin-menu.inc
koha-tmpl/intranet-tmpl/prog/en/includes/columns_settings.inc [new file with mode: 0644]
koha-tmpl/intranet-tmpl/prog/en/js/datatables.js
koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt
koha-tmpl/intranet-tmpl/prog/en/modules/admin/columns_settings.tt [new file with mode: 0644]

diff --git a/C4/Utils/DataTables/ColumnsSettings.pm b/C4/Utils/DataTables/ColumnsSettings.pm
new file mode 100644 (file)
index 0000000..8b8c79f
--- /dev/null
@@ -0,0 +1,106 @@
+package C4::Utils::DataTables::ColumnsSettings;
+
+use Modern::Perl;
+use List::Util qw( first );
+use YAML;
+use C4::Context;
+use Koha::Database;
+
+sub get_yaml {
+    my $yml_path =
+      C4::Context->config('intranetdir') . '/admin/columns_settings.yml';
+    my $yaml = eval { YAML::LoadFile($yml_path) };
+    warn
+"ERROR: the yaml file for DT::ColumnsSettings is not correctly formated: $@"
+      if $@;
+    return $yaml;
+}
+
+sub get_columns {
+    my ( $module, $page, $tablename ) = @_;
+
+    my $list = get_yaml;
+
+    my $schema = Koha::Database->new->schema;
+
+    my $rs = $schema->resultset('ColumnsSetting')->search(
+        {
+            module    => $module,
+            page      => $page,
+            tablename => $tablename,
+        }
+    );
+
+    while ( my $c = $rs->next ) {
+        my $column = first { $c->columnname eq $_->{columnname} }
+        @{ $list->{modules}{ $c->module }{ $c->page }{ $c->tablename } };
+        $column->{is_hidden}         = $c->is_hidden;
+        $column->{cannot_be_toggled} = $c->cannot_be_toggled;
+    }
+
+    return $list->{modules}{$module}{$page}{$tablename} || [];
+}
+
+sub get_modules {
+    my $list = get_yaml;
+
+    my $schema = Koha::Database->new->schema;
+    my $rs     = $schema->resultset('ColumnsSetting')->search;
+
+    while ( my $c = $rs->next ) {
+        my $column = first { $c->columnname eq $_->{columnname} }
+        @{ $list->{modules}{ $c->module }{ $c->page }{ $c->tablename } };
+        $column->{is_hidden}         = $c->is_hidden;
+        $column->{cannot_be_toggled} = $c->cannot_be_toggled;
+    }
+
+    return $list->{modules};
+}
+
+sub update_columns {
+    my ($params) = @_;
+    my $columns = $params->{columns};
+
+    my $schema = Koha::Database->new->schema;
+
+    for my $c (@$columns) {
+        $c->{is_hidden}         //= 0;
+        $c->{cannot_be_toggled} //= 0;
+
+        my $column = $schema->resultset('ColumnsSetting')->search(
+            {
+                module     => $c->{module},
+                page       => $c->{page},
+                tablename  => $c->{tablename},
+                columnname => $c->{columnname},
+            }
+        );
+        if ( $column->count ) {
+            $column = $column->first;
+            $column->update(
+                {
+                    module            => $c->{module},
+                    page              => $c->{page},
+                    tablename         => $c->{tablename},
+                    columnname        => $c->{columnname},
+                    is_hidden         => $c->{is_hidden},
+                    cannot_be_toggled => $c->{cannot_be_toggled},
+                }
+            );
+        }
+        else {
+            $schema->resultset('ColumnsSetting')->create(
+                {
+                    module            => $c->{module},
+                    page              => $c->{page},
+                    tablename         => $c->{tablename},
+                    columnname        => $c->{columnname},
+                    is_hidden         => $c->{is_hidden},
+                    cannot_be_toggled => $c->{cannot_be_toggled},
+                }
+            );
+        }
+    }
+}
+
+1;
diff --git a/Koha/Template/Plugin/ColumnsSettings.pm b/Koha/Template/Plugin/ColumnsSettings.pm
new file mode 100644 (file)
index 0000000..4617969
--- /dev/null
@@ -0,0 +1,55 @@
+package Koha::Template::Plugin::ColumnsSettings;
+
+# This file is part of Koha.
+#
+# Copyright BibLibre 2014
+#
+# 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 3 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, see <http://www.gnu.org/licenses>.
+
+use Modern::Perl;
+
+use Template::Plugin;
+use base qw( Template::Plugin );
+
+use YAML qw( LoadFile );
+use JSON qw( to_json );
+
+use C4::Context qw( config );
+use C4::Utils::DataTables::ColumnsSettings;
+
+=pod
+
+This plugin allows to get the column configuration for a table.
+
+First, include the line '[% USE Tables %]' at the top
+of the template to enable the plugin.
+
+To use, call ColumnsSettings.GetColumns with the module, the page and the table where the template is called.
+
+For example: [% ColumnsSettings.GetColumns( 'circ', 'circulation', 'holdst' ) %]
+
+=cut
+
+sub GetColumns {
+    my ( $self, $module, $page, $table, $format ) = @_;
+    $format //= q{};
+
+    my $columns = C4::Utils::DataTables::ColumnsSettings::get_columns( $module, $page, $table );
+
+    return $format eq 'json'
+        ? to_json( $columns )
+        : $columns
+}
+
+1;
diff --git a/admin/columns_settings.pl b/admin/columns_settings.pl
new file mode 100755 (executable)
index 0000000..c0c117b
--- /dev/null
@@ -0,0 +1,62 @@
+#!/usr/bin/perl
+
+use Modern::Perl;
+use CGI;
+use YAML qw( LoadFile );
+use C4::Auth;
+use C4::Context;
+use C4::Output;
+use C4::Utils::DataTables::ColumnsSettings qw( get_modules );
+my $input = new CGI;
+
+my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
+    {
+        template_name   => "admin/columns_settings.tt",
+        query           => $input,
+        type            => "intranet",
+        authnotrequired => 0,
+        flagsrequired   => { parameters => 'parameters_remaining_permissions' },
+        debug           => 1,
+    }
+);
+
+my $action = $input->param('action') // 'list';
+
+if ( $action eq 'save' ) {
+    my $module = $input->param('module');
+    my @columnids = $input->param("columnid");
+    my @columns;
+    for my $columnid (@columnids) {
+        next unless $columnid =~ m|^([^_]*)_([^_]*)_(.*)$|;
+        my $is_hidden = $input->param( $columnid . '_hidden' ) // 0;
+        my $cannot_be_toggled =
+          $input->param( $columnid . '_cannot_be_toggled' ) // 0;
+        push @columns,
+          {
+            module            => $module,
+            page              => $1,
+            tablename         => $2,
+            columnname        => $3,
+            is_hidden         => $is_hidden,
+            cannot_be_toggled => $cannot_be_toggled,
+          };
+    }
+
+    C4::Utils::DataTables::ColumnsSettings::update_columns(
+        {
+            columns => \@columns,
+        }
+    );
+
+    $action = 'list';
+}
+
+if ( $action eq 'list' ) {
+    my $modules = C4::Utils::DataTables::ColumnsSettings::get_modules;
+    $template->param(
+        panel   => ( $input->param('panel') || 0 ),
+        modules => $modules,
+    );
+}
+
+output_html_with_http_headers $input, $cookie, $template->output;
diff --git a/admin/columns_settings.yml b/admin/columns_settings.yml
new file mode 100644 (file)
index 0000000..91d69f4
--- /dev/null
@@ -0,0 +1,10 @@
+modules:
+  module_name:
+    page_name:
+      table_id:
+        -
+          columnname: my_column_name
+        -
+          columnname: my_other_column_name
+          cannot_be_toggled: 1
+          cannot_be_modified: 1
index ebd345c..8d667e0 100644 (file)
@@ -62,6 +62,7 @@
        <!-- <li><a href="/cgi-bin/koha/admin/printers.pl">Network Printers</a></li> -->
     <li><a href="/cgi-bin/koha/admin/z3950servers.pl">Z39.50 client targets</a></li>
     <li><a href="/cgi-bin/koha/admin/didyoumean.pl">Did you mean?</a></li>
+    <li><a href="/cgi-bin/koha/admin/columns_settings.pl">Columns settings</a></li>
 </ul>
 </div>
 </div>
diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/columns_settings.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/columns_settings.inc
new file mode 100644 (file)
index 0000000..5a62030
--- /dev/null
@@ -0,0 +1,27 @@
+[% USE ColumnsSettings %]
+
+<script type="text/javascript">
+function KohaTable(selector, dt_parameters, columns_settings) {
+    var id = 0;
+    var hidden_ids = [];
+    var excluded_ids = [];
+    $(columns_settings).each( function() {
+        if ( this['is_hidden'] == "1" ) {
+            hidden_ids.push( id );
+        }
+        if ( this['cannot_be_toggled'] == "1" ) {
+            excluded_ids.push( id );
+        }
+        id++;
+    });
+    dt_parameters[ "oColVis" ] = { "aiExclude": excluded_ids };
+    var table = $(selector).dataTable($.extend(true, {}, dataTablesDefaults, dt_parameters));
+
+    $(hidden_ids).each(function(index, value) {
+        table.fnSetColumnVis( value, false );
+    });
+
+    return table;
+}
+
+</script>
index c1224f0..49ccb74 100644 (file)
@@ -23,7 +23,7 @@ var dataTablesDefaults = {
         "sSearch"           : window.MSG_DT_SEARCH || "Search:",
         "sZeroRecords"      : window.MSG_DT_ZERO_RECORDS || "No matching records found"
     },
-    "sDom": '<"top pager"ilpf>tr<"bottom pager"ip>',
+    "sDom": 'C<"top pager"ilpf>tr<"bottom pager"ip>',
     "aLengthMenu": [[10, 20, 50, 100, -1], [10, 20, 50, 100, window.MSG_DT_ALL || "All"]],
     "iDisplayLength": 20
 };
index 217b069..54242fd 100644 (file)
        <dd>Define which servers to query for MARC data in the integrated Z39.50 client.</dd>
     <dt><a href="/cgi-bin/koha/admin/didyoumean.pl">Did you mean?</a></dt>
     <dd>Choose which plugins to use to suggest searches to patrons and staff.</dd>
+    <dt><a href="/cgi-bin/koha/admin/columns_settings.pl">Configure columns</a></dt>
+    <dd>Hide or show columns for tables.</dd>
 </dl>
 </div>
 
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/columns_settings.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/columns_settings.tt
new file mode 100644 (file)
index 0000000..5d7d133
--- /dev/null
@@ -0,0 +1,144 @@
+[% SET panel_id = 0 %]
+[% BLOCK pagelist %]
+<div class="pagelist">
+  <form method="post" action="/cgi-bin/koha/admin/columns_settings.pl">
+    <input type="hidden" name="action" value="save" />
+    <input type="hidden" name="module" value="[% modulename %]" />
+    <input type="hidden" name="panel" value="[% panel_id %]" />
+    [% SET panel_id = panel_id + 1 %]
+    [% IF module.keys and module.keys.size > 0 %]
+      [% FOR pagename IN module.keys %]
+        <h5>[% pagename %]</h5>
+        [% SET tables = module %]
+        [% IF tables.$pagename.keys and tables.$pagename.keys.size > 0 %]
+          [% FOR tablename IN tables.$pagename.keys.sort %]
+            <table>
+              <caption>[% tablename %]</caption>
+              <thead><tr><th>Column name</th><th>Is Hidden by default</th><th>Cannot be toggled</th></tr></thead>
+              <tbody>
+              [% FOR column IN tables.$pagename.$tablename %]
+                <tr>
+                  <td>
+                    [% column.columnname %]
+                    <input type="hidden" name="columnid" value="[% pagename %]_[% tablename %]_[% column.columnname %]" />
+                  </td>
+                  <td>
+                    [% IF column.is_hidden %]
+                      [% IF column.cannot_be_modified %]
+                        <input type="checkbox" name="[% pagename %]_[% tablename %]_[% column.columnname %]_hidden" value="1" checked="checked" disabled="disabled" />
+                        <input type="hidden" name="[% pagename %]_[% tablename %]_[% column.columnname %]_hidden" value="1" />
+                      [% ELSE %]
+                        <input type="checkbox" name="[% pagename %]_[% tablename %]_[% column.columnname %]_hidden" value="1" checked="checked" />
+                      [% END %]
+                    [% ELSE %]
+                      [% IF column.cannot_be_modified %]
+                        <input type="checkbox" name="[% pagename %]_[% tablename %]_[% column.columnname %]_hidden" value="1" disabled="disabled" />
+                        <input type="hidden" name="[% pagename %]_[% tablename %]_[% column.columnname %]_hidden" value="0" />
+                      [% ELSE %]
+                        <input type="checkbox" name="[% pagename %]_[% tablename %]_[% column.columnname %]_hidden" value="1" />
+                      [% END %]
+                    [% END %]
+                  </td>
+                  <td>
+                    [% IF column.cannot_be_toggled %]
+                      [% IF column.cannot_be_modified %]
+                        <input type="checkbox" name="[% pagename %]_[% tablename %]_[% column.columnname %]_cannot_be_toggled" value="1" checked="checked" disabled="disabled" />
+                        <input type="hidden" name="[% pagename %]_[% tablename %]_[% column.columnname %]_cannot_be_toggled" value="1" />
+                      [% ELSE %]
+                        <input type="checkbox" name="[% pagename %]_[% tablename %]_[% column.columnname %]_cannot_be_toggled" value="1" checked="checked" />
+                      [% END %]
+                    [% ELSE %]
+                      [% IF column.cannot_be_modified %]
+                        <input type="checkbox" name="[% pagename %]_[% tablename %]_[% column.columnname %]_cannot_be_toggled" value="1" disabled="disabled" />
+                        <input type="hidden" name="[% pagename %]_[% tablename %]_[% column.columnname %]_cannot_be_toggled" value="0" />
+                      [% ELSE %]
+                        <input type="checkbox" name="[% pagename %]_[% tablename %]_[% column.columnname %]_cannot_be_toggled" value="1" />
+                      [% END %]
+                    [% END %]
+                  </td>
+                </tr>
+              [% END %]
+              </tbody>
+            </table>
+          [% END %]
+          <input type="submit" value="Save" />
+        [% ELSE %]
+          There is no table to configure for this module.
+        [% END %]
+      [% END %]
+    [% ELSE %]
+        There is no page using the table configuration in this module.
+    [% END %]
+  </form>
+</div>
+[% END %]
+
+[% INCLUDE 'doc-head-open.inc' %]
+<title>Koha &rsaquo; Administration &rsaquo; Columns settings</title>
+[% INCLUDE 'doc-head-close.inc' %]
+<script type="text/javascript">
+    $(document).ready( function() {
+        var accordion = $( "#modules" ).accordion({
+            collapsible: true,
+            autoHeight: false,
+            header: "h3",
+            active: [% panel %]
+        });
+    });
+</script>
+</head>
+<body id="admin_tables" class="admin">
+[% INCLUDE 'header.inc' %]
+[% INCLUDE 'cat-search.inc' %]
+<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a> &rsaquo; Columns settings</div>
+
+<div id="doc3" class="yui-t2">
+  <div id="bd">
+    <div id="yui-main">
+      <div class="yui-b">
+        <h2>Columns settings</h2>
+        <div id="modules">
+          <h3><a href="#acqui">Acquisition</a></h3>
+          <div id="acqui">
+            <h4>Acquisition tables</h4>
+            [% PROCESS pagelist module=modules.acqui modulename="acqui" %]
+          </div>
+
+          <h3><a href="#admin">Administration</a></h3>
+          <div id="admin">
+            <h4>Administration tables</h4>
+            [% PROCESS pagelist module=modules.admin modulename="admin" %]
+          </div>
+
+          <h3><a href="#authorities">Authorities</a></h3>
+          <div id="authorities">
+            <h4>Authorities tables</h4>
+            [% PROCESS pagelist module=modules.authorities modulename="authorities" %]
+          </div>
+
+          <h3><a href="#catalog">Catalog</a></h3>
+          <div id="catalogue">
+            <h4>Catalogue tables</h4>
+            [% PROCESS pagelist module=modules.catalogue modulename="catalogue" %]
+          </div>
+
+          <h3><a href="#cataloguing">Cataloging</a></h3>
+          <div id="cataloguing">
+            <h4>Cataloguing tables</h4>
+            [% PROCESS pagelist module=modules.cataloguing modulename="cataloguing" %]
+          </div>
+
+          <h3><a href="#circulation">Circulation</a></h3>
+          <div id="circulation">
+            <h4>Circulation tables</h4>
+            [% PROCESS pagelist module=modules.circ modulename="circ" %]
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <div class="yui-b">
+      [% INCLUDE 'admin-menu.inc' %]
+    </div>
+  </div>
+[% INCLUDE 'intranet-bottom.inc' %]