Bugzilla – Attachment 62506 Details for
Bug 18346
Improved web installer containing basic and advanced setup modes
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 18346 - Implemented basic and advanced setup modes for step 3 of the web installer
Bug-18346---Implemented-basic-and-advanced-setup-m.patch (text/plain), 48.67 KB, created by
Alex Buckley
on 2017-04-20 22:51:52 UTC
(
hide
)
Description:
Bug 18346 - Implemented basic and advanced setup modes for step 3 of the web installer
Filename:
MIME Type:
Creator:
Alex Buckley
Created:
2017-04-20 22:51:52 UTC
Size:
48.67 KB
patch
obsolete
>From 6d03b7d4025a502f4bfeba84eb7f5005a4e6beac Mon Sep 17 00:00:00 2001 >From: Alex Buckley <alexbuckley@catalyst.net.nz> >Date: Thu, 9 Feb 2017 17:32:29 +0100 >Subject: [PATCH] Bug 18346 - Implemented basic and advanced setup modes for > step 3 of the web installer > >1. Drop and recreate your database >2. Clear memcached >3. Run through the web installer up to the start of step 3 >4. Notice that the 'Choose your setup' page there are only 2 >radiobutton options on the page: UNIMARC and MARC21 and neither are >selected by default >5. Select MARC21 and click 'Next' >6. The 'Select default settings' page appears. Notice that the top >checkboxes under the 'Mandatory' headings are selected by default (but can >be unselected and checkboxes under the 'optional' header are not >selected by default and can be selected >7. Do not select any checkboxes, leave the default checkboxes selected >and click the 'Import' button >8. The 'Selected data added' page appears click 'Finish' button >9. Apply patches attached to this bug report, also apply bug 18039 >10. Repeat steps 1, and 3 >11. Notice the 'Choose your setup' page has 4 radiobutton options, the >two new options are 'Basic' and 'Advanced', with 'Basic' selected by >default. Also notice that 'MARC21' radiobutton is selected by default. >12. Click 'Next' button >13. Notice on the 'Selecting default settings' page instead of default >selected radiobuttons under the header of 'Mandatory' there are bulleted >descriptions of files under the header 'Default'. As shown in the >screenshots in the '9.1.1. MARC21 Basic setup' section of this document: https://koha-community.org/manual/installation/html/web_installer_marc21_setup.html >Also notice as you scroll down there are unselected radiobuttons under >the 'Optional' heading >14. Do not select anything and click the 'Import' button >15. The 'Selected data added' page appears click the 'Finish' button >16. Repeat steps 1,2,3 >17. Select 'Advanced' and 'MARC21' on 'Choose your setup' page >18. Notice that instead of bulletpoints there are now unselected >radiobuttons under the 'default' heading on the 'Select default >settings' page, and no radiobutton on this page is selected. i.e. the >page should look similar to the screenshot under the '9.1.2. MARC21 >Advanced setup' here: https://koha-community.org/manual/installation/html/web_installer_marc21_setup.html >19. Manually select all radiobuttons under the 'Default' heading and >select 'Import' button >--- > .../data/mysql/en/optional/patron_categories.sql | 2 +- > .../data/mysql/en/optional/patron_categories.txt | 6 +- > .../data/mysql/en/optional/sample_holidays.txt | 5 +- > .../data/mysql/en/optional/sample_libraries.txt | 2 +- > .../mysql/en/optional/sample_z3950_servers.txt | 1 + > installer/install.pl | 357 ++++++++++++--------- > .../intranet-tmpl/prog/en/includes/calendar.inc | 2 +- > .../prog/en/includes/installer-doc-head-close.inc | 15 + > .../prog/en/modules/admin/categories.tt | 2 +- > .../prog/en/modules/installer/step3.tt | 299 ++++++++++------- > .../intranet-tmpl/prog/en/modules/intranet-main.tt | 2 - > xt/sample_notices.t | 2 +- > 12 files changed, 413 insertions(+), 282 deletions(-) > >diff --git a/installer/data/mysql/en/optional/patron_categories.sql b/installer/data/mysql/en/optional/patron_categories.sql >index 56439b4..57a00da 100644 >--- a/installer/data/mysql/en/optional/patron_categories.sql >+++ b/installer/data/mysql/en/optional/patron_categories.sql >@@ -1,4 +1,4 @@ >-INSERT INTO `categories` (`categorycode`, `description`, `enrolmentperiod`, `upperagelimit`, `dateofbirthrequired`, `finetype`, `bulk`, `enrolmentfee`, `overduenoticerequired`, `issuelimit`, `reservefee`, `category_type`) VALUES >+INSERT INTO `categories` (`categorycode`, `description`, `enrolmentperiod`, `upperagelimit`, `dateofbirthrequired`, `finetype`, `bulk`, `enrolmentfee`, `overduenoticerequired`, `issuelimit`, `reservefee`, `category_type`) VALUES > > -- Adult Patrons > ('PT','Patron',99,999,18,NULL,NULL,'0.000000',1,NULL,'0.000000','A'), >diff --git a/installer/data/mysql/en/optional/patron_categories.txt b/installer/data/mysql/en/optional/patron_categories.txt >index b94941a..45102b3 100644 >--- a/installer/data/mysql/en/optional/patron_categories.txt >+++ b/installer/data/mysql/en/optional/patron_categories.txt >@@ -1,6 +1,4 @@ >-Sample patron types and categories: >- >-Type: Categories: >+Sample patron types and categories. Types are currently hardcoded but you can manage categories after installation from the administration module. > > Adult patron - default patron type > PT - Patron >@@ -21,5 +19,3 @@ Professional - a member of an organization (organization is guarantor) > T - Teacher > S - Staff > B - Board >- >-Types are currently hardcoded, but you can add/edit/delete categories after installation from the administration module. >diff --git a/installer/data/mysql/en/optional/sample_holidays.txt b/installer/data/mysql/en/optional/sample_holidays.txt >index a2d2de9..2f478e1 100644 >--- a/installer/data/mysql/en/optional/sample_holidays.txt >+++ b/installer/data/mysql/en/optional/sample_holidays.txt >@@ -1,4 +1 @@ >-Sample holidays: >- Sundays >- Christmas >- New Year's >+Sample holidays: Sunday, Christmas, New Year's >diff --git a/installer/data/mysql/en/optional/sample_libraries.txt b/installer/data/mysql/en/optional/sample_libraries.txt >index cbaf05c..2a1bd9a 100644 >--- a/installer/data/mysql/en/optional/sample_libraries.txt >+++ b/installer/data/mysql/en/optional/sample_libraries.txt >@@ -1 +1 @@ >-A few sample libraries. >+Sample libraries. >diff --git a/installer/data/mysql/en/optional/sample_z3950_servers.txt b/installer/data/mysql/en/optional/sample_z3950_servers.txt >index a0bab98..b7a48c0 100644 >--- a/installer/data/mysql/en/optional/sample_z3950_servers.txt >+++ b/installer/data/mysql/en/optional/sample_z3950_servers.txt >@@ -1,3 +1,4 @@ >+Allow access to the following servers to search and download record information: > LIBRARY OF CONGRESS > LIBRARY OF CONGRESS NAMES (authority records) > LIBRARY OF CONGRESS SUBJECTS (authority records) >diff --git a/installer/install.pl b/installer/install.pl >index 508496a..7745f94 100755 >--- a/installer/install.pl >+++ b/installer/install.pl >@@ -1,5 +1,22 @@ > #!/usr/bin/perl > >+# This file is part of Koha. >+# >+# Copyright (C) 2017 Catalyst IT >+# >+# 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 strict; > use warnings; > use diagnostics; >@@ -40,10 +57,11 @@ if ( defined($language) ) { > my $installer = C4::Installer->new(); > my %info; > $info{'dbname'} = C4::Context->config("database"); >-$info{'dbms'} = >- ( C4::Context->config("db_scheme") >+$info{'dbms'} = ( >+ C4::Context->config("db_scheme") > ? C4::Context->config("db_scheme") >- : "mysql" ); >+ : "mysql" >+); > $info{'hostname'} = C4::Context->config("hostname"); > $info{'port'} = C4::Context->config("port"); > $info{'user'} = C4::Context->config("user"); >@@ -65,12 +83,14 @@ my $dbh = DBI->connect( > ); > > if ( $step && $step == 1 ) { >+ > #First Step (for both fresh installations and upgrades) > #Checking ALL perl Modules and services needed are installed. > #Whenever there is an error, adding a report to the page > my $op = $query->param('op') || 'noop'; >- $template->param( language => 1 ); >- $template->param( 'checkmodule' => 1 ); # we start with the assumption that there are no problems and set this to 0 if there are >+ $template->param( language => 1 ); >+ $template->param( 'checkmodule' => 1 ) >+ ; # we start with the assumption that there are no problems and set this to 0 if there are > > unless ( $] >= 5.010000 ) { # Bug 7375 > $template->param( problems => 1, perlversion => 1, checkmodule => 0 ); >@@ -80,11 +100,11 @@ if ( $step && $step == 1 ) { > $perl_modules->versions_info; > > my $modules = $perl_modules->get_attr('missing_pm'); >- if (scalar(@$modules)) { >- my @components = (); >+ if ( scalar(@$modules) ) { >+ my @components = (); > my $checkmodule = 1; > foreach (@$modules) { >- my ($module, $stats) = each %$_; >+ my ( $module, $stats ) = each %$_; > $checkmodule = 0 if $stats->{'required'}; > push( > @components, >@@ -96,14 +116,18 @@ if ( $step && $step == 1 ) { > } > ); > } >- @components = sort {$a->{'name'} cmp $b->{'name'}} @components; >- $template->param( missing_modules => \@components, checkmodule => $checkmodule, op => $op ); >+ @components = sort { $a->{'name'} cmp $b->{'name'} } @components; >+ $template->param( >+ missing_modules => \@components, >+ checkmodule => $checkmodule, >+ op => $op >+ ); > } > } > elsif ( $step && $step == 2 ) { >-# >-#STEP 2 Check Database connection and access >-# >+ >+ #STEP 2 Check Database connection and access >+ > $template->param(%info); > my $checkdb = $query->param("checkdb"); > $template->param( 'dbconnection' => $checkdb ); >@@ -128,7 +152,9 @@ elsif ( $step && $step == 2 ) { > my $grantaccess; > while ( my ($line) = $rq->fetchrow ) { > my $dbname = $info{dbname}; >- if ( $line =~ m/^GRANT (.*?) ON `$dbname`\.\*/ || index( $line, '*.*' ) > 0 ) { >+ if ( $line =~ m/^GRANT (.*?) ON `$dbname`\.\*/ >+ || index( $line, '*.*' ) > 0 ) >+ { > $grantaccess = 1 > if ( > index( $line, 'ALL PRIVILEGES' ) > 0 >@@ -163,23 +189,28 @@ elsif ( $step && $step == 2 ) { > } > } > $template->param( "checkgrantaccess" => $grantaccess ); >- } # End mysql connect check... >- >- elsif ( $info{dbms} eq "Pg" ) { >- # Check if database has been created... >- my $rv = $dbh->do( "SELECT * FROM pg_catalog.pg_database WHERE datname = \'$info{dbname}\';" ); >- if ( $rv == 1 ) { >- $template->param( 'checkdatabasecreated' => 1 ); >- } >- >- # Check if user has all necessary grants on this database... >- my $rq = $dbh->do( "SELECT u.usesuper >- FROM pg_catalog.pg_user as u >- WHERE u.usename = \'$info{user}\';" ); >- if ( $rq == 1 ) { >- $template->param( "checkgrantaccess" => 1 ); >- } >- } # End Pg connect check... >+ } # End mysql connect check... >+ >+ elsif ( $info{dbms} eq "Pg" ) { >+ >+ # Check if database has been created... >+ my $rv = $dbh->do( >+"SELECT * FROM pg_catalog.pg_database WHERE datname = \'$info{dbname}\';" >+ ); >+ if ( $rv == 1 ) { >+ $template->param( 'checkdatabasecreated' => 1 ); >+ } >+ >+ # Check if user has all necessary grants on this database... >+ my $rq = $dbh->do( >+ "SELECT u.usesuper >+ FROM pg_catalog.pg_user as u >+ WHERE u.usename = \'$info{user}\';" >+ ); >+ if ( $rq == 1 ) { >+ $template->param( "checkgrantaccess" => 1 ); >+ } >+ } # End Pg connect check... > } > else { > $template->param( "error" => DBI::err, "message" => DBI::errstr ); >@@ -187,11 +218,9 @@ elsif ( $step && $step == 2 ) { > } > } > elsif ( $step && $step == 3 ) { >-# >-# >-# STEP 3 : database setup >-# >-# >+ >+ # STEP 3 : database setup >+ > my $op = $query->param('op'); > if ( $op && $op eq 'finished' ) { > # >@@ -203,18 +232,20 @@ elsif ( $step && $step == 3 ) { > elsif ( $op && $op eq 'finish' ) { > $installer->set_version_syspref(); > >- # Installation is finished. >- # We just deny anybody access to install >- # And we redirect people to mainpage. >- # The installer will have to relogin since we do not pass cookie to redirection. >+# Installation is finished. >+# We just deny anybody access to install >+# And we redirect people to mainpage. >+# The installer will have to relogin since we do not pass cookie to redirection. > $template->param( "$op" => 1 ); > } >+ > elsif ( $op && $op eq 'addframeworks' ) { >- # >- # 1ST install, 3rd sub-step : insert the SQL files the user has selected >- # > >- my ($fwk_language, $list) = $installer->load_sql_in_order($all_languages, $query->param('framework')); >+ # 1ST install, 3rd sub-step : insert the SQL files the user has selected >+ >+ my ( $fwk_language, $list ) = >+ $installer->load_sql_in_order( $all_languages, >+ $query->param('framework') ); > $template->param( > "fwklanguage" => $fwk_language, > "list" => $list >@@ -224,42 +255,50 @@ elsif ( $step && $step == 3 ) { > $template->param( "$op" => 1 ); > } > elsif ( $op && $op eq 'selectframeworks' ) { >- # >- # >- # 1ST install, 2nd sub-step : show the user the sql datas he can insert in the database. >- # >- # >- # (note that the term "selectframeworks is not correct. The user can select various files, not only frameworks) >- >- #Framework Selection >- #sql data for import are supposed to be located in installer/data/<language>/<level> >- # Where <language> is en|fr or any international abbreviation (provided language hash is updated... This will be a problem with internationlisation.) >- # Where <level> is a category of requirement : required, recommended optional >- # level should contain : >- # SQL File for import With a readable name. >- # txt File that explains what this SQL File is meant for. >- # Could be VERY useful to have A Big file for a kind of library. >- # But could also be useful to have some Authorised values data set prepared here. >- # Framework Selection is achieved through checking boxes. >+# >+# >+# 1ST install, 2nd sub-step : show the user the sql datas he can insert in the database. >+# >+# >+# (note that the term "selectframeworks is not correct. The user can select various files, not only frameworks) >+ >+#Framework Selection >+#sql data for import are supposed to be located in installer/data/<language>/<level> >+# Where <language> is en|fr or any international abbreviation (provided language hash is updated... This will be a problem with internationlisation.) >+# Where <level> is a category of requirement : required, recommended optional >+# level should contain : >+# SQL File for import With a readable name. >+# txt File that explains what this SQL File is meant for. >+# Could be VERY useful to have A Big file for a kind of library. >+# But could also be useful to have some Authorised values data set prepared here. >+# Framework Selection is achieved through checking boxes. > my $langchoice = $query->param('fwklanguage'); > $langchoice = $query->cookie('KohaOpacLanguage') unless ($langchoice); >- $langchoice =~ s/[^a-zA-Z_-]*//g; >+ $langchoice =~ s/[^a-zA-Z_-]*//g; > my $marcflavour = $query->param('marcflavour'); >- if ($marcflavour){ >+ if ($marcflavour) { > $installer->set_marcflavour_syspref($marcflavour); >- }; >- $marcflavour = C4::Context->preference('marcflavour') unless ($marcflavour); >+ } >+ $marcflavour = C4::Context->preference('marcflavour') >+ unless ($marcflavour); >+ > #Insert into database the selected marcflavour > undef $/; >- my ($marc_defaulted_to_en, $fwklist) = $installer->marc_framework_sql_list($langchoice, $marcflavour); >- $template->param('en_marc_frameworks' => $marc_defaulted_to_en); >- $template->param( "frameworksloop" => $fwklist ); >- $template->param( "marcflavour" => ucfirst($marcflavour)); >- >- my ($sample_defaulted_to_en, $levellist) = $installer->sample_data_sql_list($langchoice); >- $template->param( "en_sample_data" => $sample_defaulted_to_en); >- $template->param( "levelloop" => $levellist ); >- $template->param( "$op" => 1 ); >+ my ( $marc_defaulted_to_en, $fwklist ) = >+ $installer->marc_framework_sql_list( $langchoice, $marcflavour ); >+ $template->param( 'en_marc_frameworks' => $marc_defaulted_to_en ); >+ $template->param( "frameworksloop" => $fwklist ); >+ $template->param( "marcflavour" => ucfirst($marcflavour) ); >+ >+ my ( $sample_defaulted_to_en, $levellist ) = >+ $installer->sample_data_sql_list($langchoice); >+ $template->param( "en_sample_data" => $sample_defaulted_to_en ); >+ $template->param( "levelloop" => $levellist ); >+ $template->param( "$op" => 1 ); >+ >+ my $setup = $query->param('setup'); >+ $template->param( "setup" => $setup ); >+ > } > elsif ( $op && $op eq 'choosemarc' ) { > # >@@ -268,46 +307,55 @@ elsif ( $step && $step == 3 ) { > # > # > >- #Choose Marc Flavour >- #sql data are supposed to be located in installer/data/<dbms>/<language>/marcflavour/marcflavourname >- # Where <dbms> is database type according to DBD syntax >- # Where <language> is en|fr or any international abbreviation (provided language hash is updated... This will be a problem with internationlisation.) >- # Where <level> is a category of requirement : required, recommended optional >- # level should contain : >- # SQL File for import With a readable name. >- # txt File taht explains what this SQL File is meant for. >- # Could be VERY useful to have A Big file for a kind of library. >- # But could also be useful to have some Authorised values data set prepared here. >- # Marcflavour Selection is achieved through radiobuttons. >+#Choose Marc Flavour >+#sql data are supposed to be located in installer/data/<dbms>/<language>/marcflavour/marcflavourname >+# Where <dbms> is database type according to DBD syntax >+# Where <language> is en|fr or any international abbreviation (provided language hash is updated... This will be a problem with internationlisation.) >+# Where <level> is a category of requirement : required, recommended optional >+# level should contain : >+# SQL File for import With a readable name. >+# txt File taht explains what this SQL File is meant for. >+# Could be VERY useful to have A Big file for a kind of library. >+# But could also be useful to have some Authorised values data set prepared here. >+# Marcflavour Selection is achieved through radiobuttons. > my $langchoice = $query->param('fwklanguage'); >+ > $langchoice = $query->cookie('KohaOpacLanguage') unless ($langchoice); >- $langchoice =~ s/[^a-zA-Z_-]*//g; >+ $langchoice =~ s/[^a-zA-Z_-]*//g; > my $dir = >- C4::Context->config('intranetdir') . "/installer/data/$info{dbms}/$langchoice/marcflavour"; >- unless (opendir( MYDIR, $dir )) { >- if ($langchoice eq 'en') { >+ C4::Context->config('intranetdir') >+ . "/installer/data/$info{dbms}/$langchoice/marcflavour"; >+ unless ( opendir( MYDIR, $dir ) ) { >+ if ( $langchoice eq 'en' ) { > warn "cannot open MARC frameworks directory $dir"; >- } else { >+ } >+ else { > # if no translated MARC framework is available, > # default to English >- $dir = C4::Context->config('intranetdir') . "/installer/data/$info{dbms}/en/marcflavour"; >- opendir(MYDIR, $dir) or warn "cannot open English MARC frameworks directory $dir"; >+ $dir = C4::Context->config('intranetdir') >+ . "/installer/data/$info{dbms}/en/marcflavour"; >+ opendir( MYDIR, $dir ) >+ or warn "cannot open English MARC frameworks directory $dir"; > } > } > my @listdir = grep { !/^\./ && -d "$dir/$_" } readdir(MYDIR); > closedir MYDIR; >- my $marcflavour=C4::Context->preference("marcflavour"); >+ my $marcflavour = C4::Context->preference("marcflavour"); > my @flavourlist; > foreach my $marc (@listdir) { >- my %cell=( >- "label"=> ucfirst($marc), >- "code"=>uc($marc), >- "checked"=> defined($marcflavour) ? uc($marc) eq $marcflavour : 0); >+ my %cell = ( >+ "label" => ucfirst($marc), >+ "code" => uc($marc), >+ "checked" => defined($marcflavour) >+ ? uc($marc) eq $marcflavour >+ : 0 >+ ); >+ > # $cell{"description"}= do { local $/ = undef; open INPUT "<$dir/$marc.txt"||"";<INPUT> }; > push @flavourlist, \%cell; > } > $template->param( "flavourloop" => \@flavourlist ); >- $template->param( "$op" => 1 ); >+ $template->param( "$op" => 1 ); > } > elsif ( $op && $op eq 'importdatastructure' ) { > # >@@ -327,7 +375,7 @@ elsif ( $step && $step == 3 ) { > # > #Do updatedatabase And report > >- if ( ! defined $ENV{PERL5LIB} ) { >+ if ( !defined $ENV{PERL5LIB} ) { > my $find = "C4/Context.pm"; > my $path = $INC{$find}; > $path =~ s/\Q$find\E//; >@@ -335,60 +383,77 @@ elsif ( $step && $step == 3 ) { > warn "# plack? inserted PERL5LIB $ENV{PERL5LIB}\n"; > } > >- my $now = POSIX::strftime( "%Y-%m-%dT%H:%M:%S", localtime() ); >- my $logdir = C4::Context->config('logdir'); >- my $dbversion = C4::Context->preference('Version'); >+ my $now = POSIX::strftime( "%Y-%m-%dT%H:%M:%S", localtime() ); >+ my $logdir = C4::Context->config('logdir'); >+ my $dbversion = C4::Context->preference('Version'); > my $kohaversion = Koha::version; > $kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/; > > my $filename_suffix = join '_', $now, $dbversion, $kohaversion; >- my ( $logfilepath, $logfilepath_errors ) = ( chk_log($logdir, "updatedatabase_$filename_suffix"), chk_log($logdir, "updatedatabase-error_$filename_suffix") ); >+ my ( $logfilepath, $logfilepath_errors ) = ( >+ chk_log( $logdir, "updatedatabase_$filename_suffix" ), >+ chk_log( $logdir, "updatedatabase-error_$filename_suffix" ) >+ ); > >- my $cmd = C4::Context->config("intranetdir") . "/installer/data/$info{dbms}/updatedatabase.pl >> $logfilepath 2>> $logfilepath_errors"; >+ my $cmd = C4::Context->config("intranetdir") >+ . "/installer/data/$info{dbms}/updatedatabase.pl >> $logfilepath 2>> $logfilepath_errors"; > > system($cmd ); > > my $fh; >- open( $fh, "<", $logfilepath ) or die "Cannot open log file $logfilepath: $!"; >+ open( $fh, "<", $logfilepath ) >+ or die "Cannot open log file $logfilepath: $!"; > my @report = <$fh>; > close $fh; > if (@report) { >- $template->param( update_report => [ map { { line => $_ } } split( /\n/, join( '', @report ) ) ] ); >+ $template->param( update_report => >+ [ map { { line => $_ } } split( /\n/, join( '', @report ) ) ] >+ ); > $template->param( has_update_succeeds => 1 ); >- } else { >- eval{ `rm $logfilepath` }; > } >- open( $fh, "<", $logfilepath_errors ) or die "Cannot open log file $logfilepath_errors: $!"; >+ else { >+ eval { `rm $logfilepath` }; >+ } >+ open( $fh, "<", $logfilepath_errors ) >+ or die "Cannot open log file $logfilepath_errors: $!"; > @report = <$fh>; > close $fh; > if (@report) { >- $template->param( update_errors => [ map { { line => $_ } } split( /\n/, join( '', @report ) ) ] ); >+ $template->param( update_errors => >+ [ map { { line => $_ } } split( /\n/, join( '', @report ) ) ] >+ ); > $template->param( has_update_errors => 1 ); >- warn "The following errors were returned while attempting to run the updatedatabase.pl script:\n"; >+ warn >+"The following errors were returned while attempting to run the updatedatabase.pl script:\n"; > foreach my $line (@report) { warn "$line\n"; } >- } else { >- eval{ `rm $logfilepath_errors` }; >+ } >+ else { >+ eval { `rm $logfilepath_errors` }; > } > $template->param( $op => 1 ); > } > else { >- # >- # check whether it's a 1st install or an update >- # >- #Check if there are enough tables. >- # Paul has cleaned up tables so reduced the count >- #I put it there because it implied a data import if condition was not satisfied. >+# >+# check whether it's a 1st install or an update >+# >+#Check if there are enough tables. >+# Paul has cleaned up tables so reduced the count >+#I put it there because it implied a data import if condition was not satisfied. > my $dbh = DBI->connect( > "DBI:$info{dbms}:dbname=$info{dbname};host=$info{hostname}" > . ( $info{port} ? ";port=$info{port}" : "" ) > . ( $info{tlsoptions} ? $info{tlsoptions} : "" ), > $info{'user'}, $info{'password'} > ); >- my $rq; >- if ( $info{dbms} eq 'mysql' ) { $rq = $dbh->prepare( "SHOW TABLES" ); } >- elsif ( $info{dbms} eq 'Pg' ) { $rq = $dbh->prepare( "SELECT * >- FROM information_schema.tables >- WHERE table_schema='public' and table_type='BASE TABLE';" ); } >+ my $rq; >+ if ( $info{dbms} eq 'mysql' ) { $rq = $dbh->prepare("SHOW TABLES"); } >+ elsif ( $info{dbms} eq 'Pg' ) { >+ $rq = $dbh->prepare( >+ "SELECT * >+ FROM information_schema.tables >+ WHERE table_schema='public' and table_type='BASE TABLE';" >+ ); >+ } > $rq->execute; > my $data = $rq->fetchall_arrayref( {} ); > my $count = scalar(@$data); >@@ -399,23 +464,24 @@ elsif ( $step && $step == 3 ) { > $template->param( "count" => $count, "proposeimport" => 1 ); > } > else { >- # >- # we have tables, propose to select files to upload or updatedatabase >- # >+ # >+ # we have tables, propose to select files to upload or updatedatabase >+ # > $template->param( "count" => $count, "default" => 1 ); >- # >- # 1st part of step 3 : check if there is a databaseversion systempreference >- # if there is, then we just need to upgrade >- # if there is none, then we need to install the database >- # >- if (C4::Context->preference('Version')) { >+ # >+ # 1st part of step 3 : check if there is a databaseversion systempreference >+ # if there is, then we just need to upgrade >+ # if there is none, then we need to install the database >+ # >+ if ( C4::Context->preference('Version') ) { > my $dbversion = C4::Context->preference('Version'); > $dbversion =~ /(.*)\.(..)(..)(...)/; > $dbversion = "$1.$2.$3.$4"; >- $template->param("upgrading" => 1, >- "dbversion" => $dbversion, >- "kohaversion" => Koha::version(), >- ); >+ $template->param( >+ "upgrading" => 1, >+ "dbversion" => $dbversion, >+ "kohaversion" => Koha::version(), >+ ); > } > } > } >@@ -433,7 +499,8 @@ else { > if ( $rq->execute ) { > my ($version) = $rq->fetchrow; > if ($version) { >- print $query->redirect("/cgi-bin/koha/installer/install.pl?step=3"); >+ print $query->redirect( >+ "/cgi-bin/koha/installer/install.pl?step=3"); > exit; > } > } >@@ -441,13 +508,15 @@ else { > } > output_html_with_http_headers $query, $cookie, $template->output; > >-sub chk_log { #returns a logfile in $dir or - if that failed - in temp dir >- my ($dir, $name) = @_; >- my $fn=$dir.'/'.$name.'.log'; >- if( ! open my $fh, '>', $fn ) { >- $name.= '_XXXX'; >+sub chk_log { #returns a logfile in $dir or - if that failed - in temp dir >+ my ( $dir, $name ) = @_; >+ my $fn = $dir . '/' . $name . '.log'; >+ if ( !open my $fh, '>', $fn ) { >+ $name .= '_XXXX'; > require File::Temp; >- ($fh, $fn)= File::Temp::tempfile( $name, TMPDIR => 1, SUFFIX => '.log'); >+ ( $fh, $fn ) = >+ File::Temp::tempfile( $name, TMPDIR => 1, SUFFIX => '.log' ); >+ > #if this should not work, let croak take over > } > return $fn; >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/calendar.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/calendar.inc >index f6d9e9b..a4bbe62 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/calendar.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/calendar.inc >@@ -6,7 +6,7 @@ var debug = "[% debug %]"; > var dformat = "[% dateformat %]"; > var sentmsg = 0; > if (debug > 1) {alert("dateformat: " + dformat + "\ndebug is on (level " + debug + ")");} >-var MSG_PLEASE_ENTER_A_VALID_DATE = _("Please enter a valid date (should match %s)."); >+var MSG_PLEASE_ENTER_A_VALID_DATE = (_("Please enter a valid date (should match %s).")); > > function is_valid_date(date) { > // An empty string is considered as a valid date for convenient reasons. >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/installer-doc-head-close.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/installer-doc-head-close.inc >index a4b435c..60d0e66 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/installer-doc-head-close.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/installer-doc-head-close.inc >@@ -1,5 +1,9 @@ > <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> > <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /> >+<link rel="stylesheet" type="text/css" href="[% interface %]/lib/jquery/jquery-ui-1.11.4.min.css" /> >+<link rel="stylesheet" type="text/css" href="[% interface %]/lib/bootstrap/bootstrap.min.css" /> >+<link rel="stylesheet" type="text/css" href="[% interface %]/lib/font-awesome/css/font-awesome.min.css" /> >+<link rel="stylesheet" type="text/css" media="print" href="[% interface %]/[% theme %]/css/print.css" /> > <style type="text/css" media="screen"> > > [% IF ( login ) %] >@@ -69,6 +73,17 @@ td input { font-size: 1.5em; } > > </style> > >+<script type="text/javascript" src="[% interface %]/lib/jquery/jquery-2.2.3.min.js"></script> >+<script type="text/javascript" src="[% interface %]/lib/jquery/jquery-migrate-1.3.0.min.js"></script> >+<script type="text/javascript" src="[% interface %]/lib/jquery/jquery-ui-1.11.4.min.js"></script> >+<script type="text/javascript" src="[% interface %]/lib/shortcut/shortcut.js"></script> >+<script type="text/javascript" src="[% interface %]/lib/jquery/plugins/jquery.cookie.min.js"></script> >+<script type="text/javascript" src="[% interface %]/lib/jquery/plugins/jquery.highlight-3.js"></script> >+<script type="text/javascript" src="[% interface %]/lib/bootstrap/bootstrap.min.js"></script> >+<script type="text/javascript" src="[% interface %]/lib/jquery/plugins/jquery.validate.min.js"></script> >+<!-- koha core js --> >+<script type="text/javascript" src="[% interface %]/[% theme %]/js/staff-global.js"></script> >+ > <script type="text/javascript"> > //<![CDATA[ > function _(s) { return s } // dummy function for gettext >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categories.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categories.tt >index 2c2863b..e33b36f 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categories.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categories.tt >@@ -93,7 +93,7 @@ > </li> > <li> > <label for="enrolmentperioddate" style="width:6em;">Until date: </label> >- <input type="text" class="enrollmentperiod" name="enrolmentperioddate" id="enrolmentperioddate" value="[% category.enrolmentperioddate | $KohaDates %]" /> >+ <input type="text" class="enrollmentperiod datepicker" name="enrolmentperioddate" id="enrolmentperioddate" value="[% category.enrolmentperioddate | $KohaDates %]" /> > </li> > </ol> > </fieldset> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/installer/step3.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/installer/step3.tt >index 0ec24cc..f03e37c 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/installer/step3.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/installer/step3.tt >@@ -2,129 +2,161 @@ > [% IF ( finish ) %]<meta http-equiv="refresh" content="10; url=/cgi-bin/koha/mainpage.pl">[% END %] > [% INCLUDE 'installer-doc-head-close.inc' %] > <div> >-<h1 id="logo"><img alt="Koha" src="[% interface %]/[% theme %]/img/koha.org-logo.gif" /> Web installer › Step 3</h1> >+<h1 id="logo"><img alt="Koha" src="[% interface %]/[% theme %]/img/koha.org-logo.gif" /> Koha web installer › Step 3</h1> > > [% IF ( selectframeworks ) %] > <script type="text/javascript"> >- //<![CDATA[ >+//<![CDATA[ > >- var surl = unescape(window.location.pathname); >+var surl = unescape(window.location.pathname); > >- function doLoad() >- { >- // the timeout value should be the same as in the "refresh" meta-tag >- setTimeout( "refresh()", 2*1000 ); >- } >+function doLoad() >+{ >+ // the timeout value should be the same as in the "refresh" meta-tag >+ setTimeout( "refresh()", 2*1000 ); >+} > >- function refresh(value) >- { >- // The argument to the location.reload function determines >- // if the browser should retrieve the document from the >- // web-server. In our example all we need to do is cause >- // the JavaScript block in the document body to be >- // re-evaluated. If we needed to pull the document from >- // the web-server again (such as where the document contents >- // change dynamically) we would pass the argument as 'true'. >- // >- surl=surl+'?step=3&op=selectframeworks&fwklanguage='+value; >- >- window.location.replace( surl ); >- } >+function refresh(value) >+{ >+ // The argument to the location.reload function determines >+ // if the browser should retrieve the document from the >+ // web-server. In our example all we need to do is cause >+ // the JavaScript block in the document body to be >+ // re-evaluated. If we needed to pull the document from >+ // the web-server again (such as where the document contents >+ // change dynamically) we would pass the argument as 'true'. >+ // >+ surl=surl+'?step=3&op=selectframeworks&fwklanguage='+value; >+ >+ window.location.replace( surl ); >+} > >- function selectAllFrameworks() >+function selectAllFrameworks() >+{ >+ // A handy short link that selects all available checkboxes >+ // on the page. >+ // >+ var checkboxes = document.getElementsByTagName("input"); >+ for (var i = 0; i < checkboxes.length; i++) > { >- // A handy short link that selects all available checkboxes >- // on the page. >- // >- var checkboxes = document.getElementsByTagName("input"); >- for (var i = 0; i < checkboxes.length; i++) >+ if (checkboxes[i].type == 'checkbox') > { >- if (checkboxes[i].type == 'checkbox') >- { >- checkboxes[i].checked = true; >- } >+ checkboxes[i].checked = true; > } >- >- // Prevent event propergation. >- return false; > } > >- function Hide(link) >- { >- // Toggle the display of a given element on the page. >- // >- subfield = document.getElementById('bloc'+link); >- var initstyle = subfield.style.display; >- if (initstyle == 'block') subfield.style.display = 'none' ; >- if (initstyle == 'none') subfield.style.display = 'block' ; >- } >+ // Prevent event propergation. >+ return false; >+} >+ >+function Hide(link) >+{ >+ // Toggle the display of a given element on the page. >+ // >+ subfield = document.getElementById('bloc'+link); >+ var initstyle = subfield.style.display; >+ if (initstyle == 'block') subfield.style.display = 'none' ; >+ if (initstyle == 'none') subfield.style.display = 'block' ; >+} > >- //]]> >- </script> >+//]]> >+</script> > [% END %] >+ >+ > [% IF ( finish ) %] > <h1>Congratulations, installation complete</h1> >- <p>If this page does not redirect in 5 seconds, click <a href="/">here</a>.</p> >+ <p>If this page does not redirect in 10 seconds, click <a href="/">here</a>.</p> > [% END %] >+ >+ > [% IF ( choosemarc ) %] >- <h2 align="center">Select your MARC flavor</h2> >+ <h2 align="center">Choose your setup</h2> >+ <p>Basic setup selects recommended settings by default.</p> > <form name="frameworkselection" method="post" action="install.pl"> > <input type="hidden" name="step" value="3" /> >- <input type="hidden" name="op" value="selectframeworks" /> >- <p> >+ <input type="hidden" name="op" value="selectframeworks"/> >+ >+ <div> >+ <input type="radio" name="setup" value="Basic" checked="checked">Basic<br/> >+ <input type="radio" name="setup" value="Advanced"/>Advanced<br/> >+ </div> >+ >+ <h2 align="center">Select your MARC flavor</h2> >+ <p>MARC stands for Machine Readable Cataloging, containing information about a bibliographic record. MARC21 is more commonly used globally, whereas UNIMARC tends to be used in Europe. </p> >+ > [% FOREACH flavourloo IN flavourloop %] > <div> >- [% IF ( flavourloo.checked ) %] >- <input type="radio" name="marcflavour" value="[% flavourloo.code %]" checked /> [% flavourloo.label %] <br/> >+ [% IF ( flavourloo.label == "Unimarc") %] >+ <input type="radio" name="marcflavour" value="[% flavourloo.code %]" /> [% flavourloo.label %]<br/> > [% ELSE %] >- <input type="radio" name="marcflavour" value="[% flavourloo.code %]" /> [% flavourloo.label %] <br/> >+ <input type="radio" name="marcflavour" value="[% flavourloo.code %]" checked="checked" /> [% flavourloo.label %] <br/> > [% END %] > </div> > [% END %] >- </p> >- <p> Click 'Next' to continue <input value="Next >>" type="submit" /></p> >+ >+ <p>Click 'Next' to continue <input value="Next >>" type="submit" /></p> >+ > </form> >+ > [% END %] > > [% IF ( selectframeworks ) %] >- <h2 align="center">Selecting Default Settings</h2> >- <script type="text/javascript"> >- var linklabel = _("Select all sample data"); >- document.write('<p><a href="#" onclick="return selectAllFrameworks();">'+linklabel+'</a></p>'); >- </script> >- <form name="frameworkselection" method="post" action="install.pl"> >- <input type="hidden" name="step" value="3" /> >- <input type="hidden" name="op" value="addframeworks" /> >+ <h2 align= "center"> [% setup %] setup</h2> >+ <h2 align="center">Selecting Default Settings</h2> > >+ [% IF setup == "Advanced" %] >+ <script type="text/javascript"> >+ var linklabel = _("Select all options"); >+ document.write('<p><a href="#" onclick="return selectAllFrameworks();"><button>'+linklabel+'</button></a></p>'); >+ </script> >+ [% END %] >+ <form name="frameworkselection" method="post" action="install.pl"> >+ <input type="hidden" name="step" value="3" /> >+ <input type="hidden" name="op" value="addframeworks" /> > [% IF ( frameworksloop ) %] >- <h2>MARC frameworks: [% marcflavour %]</h2> >- [% IF ( en_marc_frameworks ) %] >- <h4><span class="error">No MARC frameworks are available for your language. >- Defaulting to the frameworks supplied for English (en)<span></h4> >- [% END %] >- [% FOREACH frameworksloo IN frameworksloop %] >- <div> >- <h3>[% frameworksloo.label %]</h3> >- [% FOREACH framework IN frameworksloo.frameworks %] >- <table style="border:1px;vertical-align:top;"> >- <tr> >- <td style="vertical-align:top;"> >- [% IF ( framework.checked ) %] >- <input type="checkbox" name="framework" value="[% framework.fwkfile %]" checked="checked" id="[% framework.fwkname %]" /> >- [% ELSE %] >- <input type="checkbox" name="framework" value="[% framework.fwkfile %]" id="[% framework.fwkname %]" /> >- [% END %] >- </td> >- <td> >- <label for="[% framework.fwkname %]"> >- [% framework.fwkdescription %] >- <em>([% framework.fwkname %])</em> >- </label> >- </td> >- </table> >- [% END %] >- </div> >- [% END %] >+ <h2>MARC frameworks: [% marcflavour %]</h2> >+ [% IF ( en_marc_frameworks ) %] >+ <h4><span class="error">No MARC frameworks are available for your language. >+ Defaulting to the frameworks supplied for English (en)<span></h4> >+ [% END %] >+ [% FOREACH frameworksloo IN frameworksloop %] >+ <div> >+ <h3>[% frameworksloo.label %]</h3> >+ [% FOREACH framework IN frameworksloo.frameworks %] >+ <table style="border:1px;vertical-align:top;"> >+ <tr> >+ <td style = "border:1px; vertical-align:top;"> >+ [% IF (frameworksloo.label == "Default") && (setup=="Basic") %] >+ <input type="hidden" name="framework" value="[% framework.fwkfile %]" id ="[%framework.fwkname%]" /> >+ [% ELSE %] >+ <input type="checkbox" name="framework" value="[% framework.fwkfile %]" id ="[%framework.fwkname%]" /> >+ [% END %] >+ </td> >+ <td> >+ [% IF (frameworksloo.label == "Default") && (setup=="Basic") %] >+ <ul> >+ <li> >+ <label for="[% framework.fwkname %]"> >+ [% framework.fwkdescription %] >+ <em>([% framework.fwkname %])</em> >+ </label> >+ </li> >+ </ul> >+ </td> >+ [% ELSE %] >+ <td> >+ <label for= "[% framework.fwkname %]"> >+ [% framework.fwkdescription %] >+ <em>([% framework.fwkname %])</em> >+ </label> >+ </td> >+ [% END %] >+ </tr> >+ </table> >+ [% END %] >+ </div> >+ [% END %] > <h2>Other data</h2> > [% END %] > [% IF ( en_sample_data ) %] >@@ -132,27 +164,49 @@ > Defaulting to the samples supplied for English (en)<span></h4> > [% END %] > [% FOREACH levelloo IN levelloop %] >- <div> >- <h3>[% levelloo.label %]</h3> >- [% FOREACH framework IN levelloo.frameworks %] >- <table style="border:1px;vertical-align:top;"> >- <tr> >- <td style="vertical-align:top;"> >- [% IF ( framework.checked ) %] >- <input type="checkbox" name="framework" value="[% framework.fwkfile %]" checked="checked" id="[% framework.fwkname %]" /> >- [% ELSE %] >- <input type="checkbox" name="framework" value="[% framework.fwkfile %]" id="[% framework.fwkname %]" /> >- [% END %] >- </td> >- <td> >- <label for="[% framework.fwkname %]"> >- [% framework.fwkdescription %] >- <em>([% framework.fwkname %])</em> >- </label> >- </td> >- </table> >- [% END %] >- </div> >+ <div> >+ <h3>[% levelloo.label %]</h3> >+ >+ [% IF (setup == "Basic" && levelloo.label == "Optional") %] >+ <script type="text/javascript"> >+ var linklabel = _("Select all options"); >+ document.write('<p><a href="#" onclick="return selectAllFrameworks();"><button>'+linklabel+'</button></a></p>'); >+ </script> >+ [% END %] >+ >+ [% FOREACH framework IN levelloo.frameworks %] >+ <table style="border:1px;vertical-align:top;"> >+ <tr> >+ <td style="vertical-align:top;"> >+ [% IF (levelloo.label == "Default" ) && (setup=="Basic")%] >+ <input type="hidden" name="framework" value="[% framework.fwkfile %]" id="[%framework.fwkname %]" /> >+ [% ELSE %] >+ <input type="checkbox" name="framework" value="[%framework.fwkfile %]" id="[%framework.fwkname%]"/> >+ [% END %] >+ </td> >+ <td> >+ [% IF (levelloo.label == "Default") && (setup=="Basic")%] >+ <ul> >+ <li> >+ <label for="[% framework.fwkname %]"> >+ [% framework.fwkdescription %] >+ <em>([% framework.fwkname %])</em> >+ </label> >+ </li> >+ </ul> >+ </td> >+ [% ELSE %] >+ <td> >+ <label for= "[% framework.fwkname %]"> >+ [% framework.fwkdescription %] >+ <em>([% framework.fwkname %])</em> >+ </label> >+ </td> >+ [% END %] >+ </tr> >+ </table> >+ [% END %] >+ </div> > [% END %] > <p>When you've made your selections, please click 'Import' below to begin the process. It may take a while to complete, > please be patient.</p> >@@ -181,7 +235,8 @@ > <form name="finish"> > <input type="hidden" name="step" value="3" /> > <input type="hidden" name="op" value="finish" /> >- <input type="submit" value="Finish" /></form> >+ <input type="submit" value="Set up Koha with the onboarding tool"/> >+ </form> > </p> > </p> > [% END %] >@@ -214,22 +269,22 @@ > </form> > [% END %] > >- > [% IF ( default ) %] > [% IF ( upgrading ) %] > <p> >- We are upgrading from Koha [% dbversion %] to [% kohaversion %], you must <a href="install.pl?step=3&op=updatestructure" class="button">update your database</a> >+ We are upgrading from Koha [% dbversion %] to [% kohaversion %], you must update your database. >+ <br> >+ <a href="install.pl?step=3&op=updatestructure" class="button"><button>Update Database</button></a> > </p> > [% ELSE %] >- <p>We are ready to do some basic configuration. Please >- <a href="install.pl?step=3&op=choosemarc" class="button">install basic configuration settings</a> >- to continue the installation. >- </p> >+ <p>We are ready to do some basic configuration. Please install some basic configuration settings to continue the installation: >+ <br> >+ <br> >+ <a href="install.pl?step=3&op=choosemarc" class="button"><button>Install Basic Configuration Settings</button></a> >+ > [% END %] > [% END %] > >- >- > [% IF ( updatestructure ) %] > <div><h2 align="center">Updating database structure</h2> > [% IF ( has_update_succeeds ) %] >@@ -251,7 +306,7 @@ > [% UNLESS ( has_update_errors ) %] > <p>Everything went OK, update done.</p> > [% END %] >-<a href="install.pl?step=3&op=finished" class="button">Continue to log in to Koha</a> >+<a href="install.pl?step=3&op=choosemarc" class="button"><button>Back to Installation</button></a> > </div> > [% END %] > >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/intranet-main.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/intranet-main.tt >index fa5cde8..a096577 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/intranet-main.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/intranet-main.tt >@@ -1,5 +1,3 @@ >-[% USE Koha %] >-[% SET footerjs = 1 %] > [% INCLUDE 'doc-head-open.inc' %] > <title>Koha staff client</title> > <link rel="stylesheet" type="text/css" href="[% interface %]/[% theme %]/css/mainpage.css" /> >diff --git a/xt/sample_notices.t b/xt/sample_notices.t >index 2653407..39e3ab2 100755 >--- a/xt/sample_notices.t >+++ b/xt/sample_notices.t >@@ -22,7 +22,7 @@ use Test::More qw(no_plan); > > > my $root_dir = 'installer/data/mysql'; >-my $base_notices_file = "en/mandatory/sample_notices.sql"; >+my $base_notices_file = "en/default/sample_notices.sql"; > my @trans_notices_files = qw( > fr-FR/1-Obligatoire/sample_notices.sql > fr-CA/obligatoire/sample_notices.sql >-- >2.1.4
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 18346
:
61666
|
62354
|
62355
|
62356
|
62357
| 62506 |
62507
|
63457