Bug 17282: Ability to create charts for SQL reports
Add a form under report's result that allow to configure and draw a chart (pie, bar, line and combination). Pie: Usefull only for a two-column report's result bar: Horizontal: Can be horizontal or vertical (check/uncheck horizontal checkbox), Group: allows to group columns (stacked bar chart), Line: show some columns as line in a bar chart (combination) line: line chart :) This patch adds 2 new js libraries: d3js and c3js: - c3.min.css - c3.min.js - d3.min.js Test plan: - Apply this patch, - execute a report, - click on show chart settings button (in the tool bar), - draw chart (click on draw button), - check the chart Features: - Include all rows (ignore pagination), - Download the chart (svg), - Choose x column and y columns, - Exclude last line (Rollup) Signed-off-by: Michal Denar <black23@gmail.com> Signed-off-by: Josef Moravec <josef.moravec@gmail.com> Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
This commit is contained in:
parent
8b1bda9ed8
commit
edb627bcf2
10 changed files with 443 additions and 0 deletions
1
koha-tmpl/intranet-tmpl/lib/d3c3/c3.min.css
vendored
Normal file
1
koha-tmpl/intranet-tmpl/lib/d3c3/c3.min.css
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.c3 svg{font:10px sans-serif;-webkit-tap-highlight-color:transparent}.c3 line,.c3 path{fill:none;stroke:#000}.c3 text{-webkit-user-select:none;-moz-user-select:none;user-select:none}.c3-bars path,.c3-event-rect,.c3-legend-item-tile,.c3-xgrid-focus,.c3-ygrid{shape-rendering:crispEdges}.c3-chart-arc path{stroke:#fff}.c3-chart-arc text{fill:#fff;font-size:13px}.c3-grid line{stroke:#aaa}.c3-grid text{fill:#aaa}.c3-xgrid,.c3-ygrid{stroke-dasharray:3 3}.c3-text.c3-empty{fill:gray;font-size:2em}.c3-line{stroke-width:1px}.c3-circle._expanded_{stroke-width:1px;stroke:#fff}.c3-selected-circle{fill:#fff;stroke-width:2px}.c3-bar{stroke-width:0}.c3-bar._expanded_{fill-opacity:.75}.c3-target.c3-focused{opacity:1}.c3-target.c3-focused path.c3-line,.c3-target.c3-focused path.c3-step{stroke-width:2px}.c3-target.c3-defocused{opacity:.3!important}.c3-region{fill:#4682b4;fill-opacity:.1}.c3-brush .extent{fill-opacity:.1}.c3-legend-item{font-size:12px}.c3-legend-item-hidden{opacity:.15}.c3-legend-background{opacity:.75;fill:#fff;stroke:#d3d3d3;stroke-width:1}.c3-title{font:14px sans-serif}.c3-tooltip-container{z-index:10}.c3-tooltip{border-collapse:collapse;border-spacing:0;background-color:#fff;empty-cells:show;-webkit-box-shadow:7px 7px 12px -9px #777;-moz-box-shadow:7px 7px 12px -9px #777;box-shadow:7px 7px 12px -9px #777;opacity:.9}.c3-tooltip tr{border:1px solid #CCC}.c3-tooltip th{background-color:#aaa;font-size:14px;padding:2px 5px;text-align:left;color:#FFF}.c3-tooltip td{font-size:13px;padding:3px 6px;background-color:#fff;border-left:1px dotted #999}.c3-tooltip td>span{display:inline-block;width:10px;height:10px;margin-right:6px}.c3-tooltip td.value{text-align:right}.c3-area{stroke-width:0;opacity:.2}.c3-chart-arcs-title{dominant-baseline:middle;font-size:1.3em}.c3-chart-arcs .c3-chart-arcs-background{fill:#e0e0e0;stroke:none}.c3-chart-arcs .c3-chart-arcs-gauge-unit{fill:#000;font-size:16px}.c3-chart-arcs .c3-chart-arcs-gauge-max,.c3-chart-arcs .c3-chart-arcs-gauge-min{fill:#777}.c3-chart-arc .c3-gauge-value{fill:#000}
|
6
koha-tmpl/intranet-tmpl/lib/d3c3/c3.min.js
vendored
Normal file
6
koha-tmpl/intranet-tmpl/lib/d3c3/c3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
5
koha-tmpl/intranet-tmpl/lib/d3c3/d3.min.js
vendored
Normal file
5
koha-tmpl/intranet-tmpl/lib/d3c3/d3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -4222,3 +4222,7 @@ span {
|
|||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
div#makechart ol li {
|
||||
list-style: none;
|
||||
}
|
||||
|
|
96
koha-tmpl/intranet-tmpl/prog/en/includes/chart.inc
Normal file
96
koha-tmpl/intranet-tmpl/prog/en/includes/chart.inc
Normal file
|
@ -0,0 +1,96 @@
|
|||
<div id="makechart" style="display:none;">
|
||||
[% supposed_x = header_row.shift.cell %]
|
||||
|
||||
<fieldset>
|
||||
<legend>Draw a chart</legend>
|
||||
<ol>
|
||||
<li>
|
||||
<label for="chart-type">Chart type</label>
|
||||
<select name="chart-type" id="chart-type">
|
||||
<option value="pie">Pie</option>
|
||||
<option value="bar">Bar</option>
|
||||
<option value="line">Line</option>
|
||||
</select>
|
||||
|
||||
<div id="chart-column-horizontal">
|
||||
<label for="horizontal">Horizontal bar:</label>
|
||||
<input id="horizontal" name="column-horizontal" type="checkbox">
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<label for="x_element">x column:</label>
|
||||
<select id="x_element" name="x">
|
||||
<option value="[% supposed_x %]" selected>[% supposed_x %]</option>
|
||||
[% FOREACH header IN header_row %]
|
||||
<option value="[% header.cell %]">[% header.cell %]</option>
|
||||
[% END %]
|
||||
</select>
|
||||
</li>
|
||||
|
||||
<div>
|
||||
<label for="include-all">Include all rows (ignore pagination)</label>
|
||||
<input id="include-all" name="chart-include-all" type="checkbox">
|
||||
</div>
|
||||
|
||||
|
||||
<label for="exclude-last">Exclude last line (Rollup)</label>
|
||||
<input id="exclude-last" name="chart-exclude-last" type="checkbox">
|
||||
|
||||
[% column = 1 %]
|
||||
<li>
|
||||
[% FOREACH header IN header_row %]
|
||||
<fieldset class="chart-column-conf" id="column_[% column %]" style="display: inline !important;">
|
||||
<legend>
|
||||
Column [% column %]
|
||||
<a class="chart-column-delete" href="#" data-column="[% column %]">
|
||||
<img src="[% interface %]/[% theme %]/img/x.png" alt="Delete" />
|
||||
</a>
|
||||
</legend>
|
||||
<div>
|
||||
<label for="y_[% column %]" >y:</label>
|
||||
<select id="y_[% column %]" name="y">
|
||||
<option value="[% supposed_x %]" selected>[% supposed_x %]</option>
|
||||
[% FOREACH h IN header_row %]
|
||||
[% IF header.cell == h.cell %]
|
||||
<option value="[% h.cell %]" selected>[% h.cell %]</option>
|
||||
[% ELSE %]
|
||||
<option value="[% h.cell %]">[% h.cell %]</option>
|
||||
[% END %]
|
||||
[% END %]
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="chart-column-group">
|
||||
[% i = 1 %]
|
||||
<label for="group_[% column %]">Group:</label>
|
||||
<select id="group_[% column %]" name="group">
|
||||
[% FOREACH h IN header_row %]
|
||||
[% IF i == column %]
|
||||
<option value="[% i %]" selected>[% i %]</option>
|
||||
[% ELSE %]
|
||||
<option value="[% i %]">[% i %]</option>
|
||||
[% END %]
|
||||
[% i = i + 1 %]
|
||||
[% END %]
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="chart-column-line">
|
||||
<label for="line_[% column %]">line:</label>
|
||||
<input class="column-line" id="column-line" name="[% header.cell %]" type="checkbox">
|
||||
</div>
|
||||
</fieldset>
|
||||
[% column = column + 1 %]
|
||||
[% END %]
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<button id="draw-chart" class="btn btn-default">Draw</button>
|
||||
</li>
|
||||
</ol>
|
||||
</fieldset>
|
||||
[% item = { cell = supposed_x } %]
|
||||
[% header_row.unshift(item) %]
|
||||
<div id="chart"></div>
|
||||
</div>
|
|
@ -60,12 +60,19 @@
|
|||
<li><a id="csv" href="/cgi-bin/koha/reports/guided_reports.pl?reports=1&phase=Export&format=csv&report_id=[% id | html %]&reportname=[% name |uri %][% PROCESS params %]">[% PROCESS 'delimiter_text.inc' %]</a></li>
|
||||
<li><a id="tab" href="/cgi-bin/koha/reports/guided_reports.pl?reports=1&phase=Export&format=tab&report_id=[% id | html %]&reportname=[% name |uri %][% PROCESS params %]">Tab separated text</a></li>
|
||||
<li><a id="ods" href="/cgi-bin/koha/reports/guided_reports.pl?reports=1&phase=Export&format=ods&report_id=[% id | html %]&reportname=[% name |uri %][% PROCESS params %]">Open Document Spreadsheet</a></li>
|
||||
[% IF (results.json) %]
|
||||
<li><a id="download-chart" href="#">Download chart</a></li>
|
||||
[% END %]
|
||||
</ul>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<a class="btn btn-default btn-sm toggle_sql" id="toggle_sql_hid" href="#"><i class="fa fa-eye"></i> Show SQL code</a>
|
||||
<a class="btn btn-default btn-sm toggle_sql" id="toggle_sql_vis" href="#" style="display:none;"><i class="fa fa-eye-slash"></i> Hide SQL code</a>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<a class="btn btn-default btn-sm toggle_chart_settings" id="toggle_chart_settings_hid" href="#"><i class="fa fa-eye"></i> Show chart settings</a>
|
||||
<a class="btn btn-default btn-sm toggle_chart_settings" id="toggle_chart_settings_vis" href="#" style="display:none;"><i class="fa fa-eye-slash"></i> Hide chart settings</a>
|
||||
</div>
|
||||
[% END %]
|
||||
|
||||
[% END %]
|
||||
|
|
|
@ -962,6 +962,12 @@
|
|||
|
||||
<h2>JSZip</h2>
|
||||
<p>The <a href="https://stuk.github.io/jszip/">JSZip</a> JavaScript library is licensed under both the <a href="https://github.com/Stuk/jszip/blob/master/LICENSE.markdown">MIT and GPLv3 Licenses</a>.</p>
|
||||
|
||||
<h2>D3.js</h2>
|
||||
<p><a href="https://d3js.org/">D3.js v3.5.17</a> is a JavaScript library for manipulating documents based on data. It is under the <a href="https://github.com/d3/d3/blob/master/LICENSE">BSD 3-clause Licence</a></p>
|
||||
|
||||
<h2>C3.js</h2>
|
||||
<p><a href="http://c3js.org/">C3.js v0.4.11</a> is a D3-based reusable chart library under the <a href="https://opensource.org/licenses/mit-license.php">MIT licence</a></p>
|
||||
</div>
|
||||
|
||||
<div id="translations">
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
[% USE KohaDates %]
|
||||
[% USE Koha %]
|
||||
[% USE ColumnsSettings %]
|
||||
[% USE JSON.Escape %]
|
||||
[% SET footerjs = 1 %]
|
||||
|
||||
[%- BLOCK area_name -%]
|
||||
[%- SWITCH area -%]
|
||||
[%- CASE 'CIRC' -%]Circulation
|
||||
|
@ -36,6 +38,7 @@
|
|||
[% Asset.css("css/reports.css") | $raw %]
|
||||
[% Asset.css("css/datatables.css") | $raw %]
|
||||
[% END %]
|
||||
[% Asset.css("../lib/d3c3/c3.min.css") | $raw %]
|
||||
</head>
|
||||
|
||||
<body id="rep_guided_reports_start" class="rep">
|
||||
|
@ -696,6 +699,7 @@ canned reports and writing custom SQL reports.</p>
|
|||
|
||||
[% IF ( execute ) %]
|
||||
<h1>[% name | html %]</h1>
|
||||
[% INCLUDE 'chart.inc' %]
|
||||
[% IF ( notes ) %]<p><span class="label">Notes:</span> [% notes | html %]</p>[% END %]
|
||||
[% IF ( unlimited_total ) %]<p><span class="label">Total number of results:</span> [% unlimited_total | html %][% IF unlimited_total > limit %] ([% limit | html %] shown)[% END %].</p>[% END %]
|
||||
<div id="sql_output" style="display:none;"><span class="label">Report SQL:</span><pre>[% sql | html %]</pre></div>
|
||||
|
@ -751,6 +755,7 @@ canned reports and writing custom SQL reports.</p>
|
|||
[% END %]
|
||||
</table>
|
||||
</form>
|
||||
|
||||
[% END %]
|
||||
[% END %]
|
||||
|
||||
|
@ -934,12 +939,44 @@ $(document).ready(function() {
|
|||
</div>
|
||||
|
||||
[% MACRO jsinclude BLOCK %]
|
||||
[% Asset.js("js/charts.js") | $raw %]
|
||||
[% Asset.js("../lib/d3c3/d3.min.js") | $raw %]
|
||||
[% Asset.js("../lib/d3c3/c3.min.js") | $raw %]
|
||||
[% INCLUDE 'calendar.inc' %]
|
||||
[% IF ( saved1 ) %]
|
||||
[% INCLUDE 'datatables.inc' %]
|
||||
[% INCLUDE 'columns_settings.inc' %]
|
||||
[% END %]
|
||||
<script>
|
||||
|
||||
function hide_bar_element() {
|
||||
$('#chart-column-horizontal').hide()
|
||||
$('.chart-column-group').each(function( index ) {
|
||||
$( this ).hide();
|
||||
});
|
||||
$('.chart-column-line').each(function( index ) {
|
||||
$( this ).hide()
|
||||
});
|
||||
}
|
||||
|
||||
function show_bar_element() {
|
||||
$('#chart-column-horizontal').show()
|
||||
$('.chart-column-group').each(function( index ) {
|
||||
$( this ).show()
|
||||
});
|
||||
$('.chart-column-line').each(function( index ) {
|
||||
$( this ).show()
|
||||
});
|
||||
}
|
||||
|
||||
function removeColumn(id) {
|
||||
$('#'+id).remove();
|
||||
|
||||
if ( $('.chart-column-conf').length == 1 ) {
|
||||
$('.chart-column-delete').remove();
|
||||
}
|
||||
}
|
||||
|
||||
var MSG_CONFIRM_DELETE = _("Are you sure you want to delete this report? This cannot be undone.");
|
||||
var group_subgroups = {};
|
||||
[% FOREACH group IN groups_with_subgroups %]
|
||||
|
@ -970,6 +1007,111 @@ $(document).ready(function() {
|
|||
|
||||
$(document).ready(function(){
|
||||
|
||||
hide_bar_element();
|
||||
|
||||
if ( $('.chart-column-conf').length == 1 ) {
|
||||
$('.chart-column-delete').remove();
|
||||
}
|
||||
|
||||
$(".chart-column-delete").on('click', function(e){
|
||||
e.preventDefault();
|
||||
removeColumn('column_' + $(this).data('column'));
|
||||
})
|
||||
|
||||
$('#download-chart').click(function() {
|
||||
var svg = '<svg>' + $('#chart svg').html() + '</svg>';
|
||||
this.href = 'data:application/octet-stream;base64,' + btoa(svg);
|
||||
this.setAttribute('download', 'chart.svg');
|
||||
});
|
||||
|
||||
$('#chart-type').change(function() {
|
||||
if ($(this).val() == 'bar') {
|
||||
show_bar_element();
|
||||
}
|
||||
else {
|
||||
hide_bar_element();
|
||||
}
|
||||
});
|
||||
|
||||
$('#download-chart').hide();
|
||||
var chart;
|
||||
|
||||
[% IF results && !errors %]
|
||||
$('#draw-chart').click(function() {
|
||||
|
||||
var btn_text = $("#draw-chart").html();
|
||||
$("#draw-chart").html(_("Loading..."));
|
||||
|
||||
var x_elements = $('select[name="x"]').val();
|
||||
var y_elements = [];
|
||||
var groups = [];
|
||||
var lines = [];
|
||||
var options = {};
|
||||
|
||||
headers = [% header_row.json %];
|
||||
|
||||
var results;
|
||||
if ($('input[name="chart-include-all"]').prop('checked')) {
|
||||
results = [% allresults.json %]
|
||||
}
|
||||
else {
|
||||
results = [% results.json %]
|
||||
}
|
||||
|
||||
if ($('input[name="chart-exclude-last"]').prop('checked')) {
|
||||
results.splice(-1, 1);
|
||||
}
|
||||
|
||||
$('select[name="y"]').each(function( index ) {
|
||||
y_elements.push( $(this).val() );
|
||||
});
|
||||
$('select[name="group"]').each(function( index ) {
|
||||
groups.push( $(this).val() );
|
||||
});
|
||||
$('.column-line').each(function( index ) {
|
||||
if ($(this).prop('checked')) {
|
||||
lines.push( $(this).attr('name') );
|
||||
}
|
||||
});
|
||||
|
||||
// Remove deleted columns from headers and results.
|
||||
var deleted_indexes = [];
|
||||
var kept_headers = [];
|
||||
$.each(headers, function(index, value) {
|
||||
if (value.cell != x_elements && $.inArray(value.cell, y_elements) === -1) {
|
||||
// This header is neither a x element nor in y elements. Don't need it.
|
||||
deleted_indexes.push(index);
|
||||
}
|
||||
else {
|
||||
kept_headers.push({cell: value.cell});
|
||||
}
|
||||
});
|
||||
|
||||
// Remove coresponding cells.
|
||||
var kept_results = [];
|
||||
$.each(results, function(index, value) {
|
||||
var line = {};
|
||||
line['cells'] = [];
|
||||
$.each(value.cells, function(i, val) {
|
||||
if ($.inArray(i, deleted_indexes) === -1) {
|
||||
line['cells'].push({cell: val.cell});
|
||||
}
|
||||
});
|
||||
kept_results.push(line);
|
||||
});
|
||||
|
||||
options.type = $('select[name="chart-type"]').val();
|
||||
options.horizontal = $('input[name="column-horizontal"]').prop('checked');
|
||||
options.lines = lines;
|
||||
|
||||
chart = create_chart(kept_headers, kept_results, x_elements, y_elements, groups, options);
|
||||
$('#chart').prepend('<div style="font-size: 1rem; text-align: center;">' + "[% name %]" + '</div>');
|
||||
$('#download-chart').show();
|
||||
$("#draw-chart").html(_(btn_text));
|
||||
$("html, body").animate({ scrollTop: $(document).height() }, "slow");
|
||||
});
|
||||
[% END %]
|
||||
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
var columns_settings = [% ColumnsSettings.GetColumns( 'reports', 'saved-sql', 'table_reports', 'json' ) | $raw %];
|
||||
|
||||
|
@ -1108,6 +1250,12 @@ $(document).ready(function() {
|
|||
$("#toggle_sql_vis").toggle();
|
||||
});
|
||||
|
||||
$(".toggle_chart_settings").click(function(){
|
||||
$("#makechart").toggle();
|
||||
$("#toggle_chart_settings_hid").toggle();
|
||||
$("#toggle_chart_settings_vis").toggle();
|
||||
});
|
||||
|
||||
$("#table_reports").delegate(".confirmdelete", 'click', function(){
|
||||
$(this).parents('tr').attr("class","warn");
|
||||
if(confirm(_("Are you sure you want to delete this saved report?"))){
|
||||
|
|
163
koha-tmpl/intranet-tmpl/prog/js/charts.js
Normal file
163
koha-tmpl/intranet-tmpl/prog/js/charts.js
Normal file
|
@ -0,0 +1,163 @@
|
|||
function create_chart(headers, results, x_element, y_elements, y_groups, options) {
|
||||
|
||||
var type = options.type;
|
||||
var horizontal = options.horizontal;
|
||||
var lines = options.lines;
|
||||
var data;
|
||||
var axis;
|
||||
|
||||
if (type != 'pie') {
|
||||
var columns = build_columns(headers, results, x_element, y_elements);
|
||||
var groups = build_group(y_elements, y_groups);
|
||||
var x_values = build_xvalues(headers, results, x_element);
|
||||
|
||||
axis = {
|
||||
x: {
|
||||
type: 'category',
|
||||
categories: x_values
|
||||
}
|
||||
};
|
||||
|
||||
data = {
|
||||
columns: columns,
|
||||
groups: groups,
|
||||
type: type,
|
||||
};
|
||||
|
||||
}
|
||||
else {
|
||||
var columns = build_pie_columns(headers, results, x_element);
|
||||
data = {
|
||||
columns: columns,
|
||||
type: type,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
if (type == 'bar') {
|
||||
var types = {};
|
||||
$.each(lines, function(index, value) {
|
||||
types[value] = 'line';
|
||||
});
|
||||
data.types = types;
|
||||
|
||||
if (horizontal) {
|
||||
axis.rotated = true;
|
||||
}
|
||||
}
|
||||
|
||||
var chart = c3.generate({
|
||||
bindto: '#chart',
|
||||
data: data,
|
||||
axis: axis,
|
||||
});
|
||||
|
||||
return chart;
|
||||
}
|
||||
|
||||
function build_pie_columns(headers, results, x_element) {
|
||||
var columns = [];
|
||||
var x_index;
|
||||
|
||||
//Get x_element index.
|
||||
$.each(headers, function(index, value) {
|
||||
if (value.cell == x_element) {
|
||||
x_index = index;
|
||||
}
|
||||
});
|
||||
|
||||
$.each(results, function(index, value) {
|
||||
var cells = value.cells;
|
||||
$.each( cells, function(i, value) {
|
||||
if (i == x_index) {
|
||||
columns[index] = [value.cell];
|
||||
}
|
||||
});
|
||||
$.each( cells, function(i, value) {
|
||||
if (i != x_index) {
|
||||
columns[index].push(value.cell);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return columns;
|
||||
}
|
||||
|
||||
function build_xvalues(headers, results, x_element) {
|
||||
var h_index;
|
||||
x_values = [];
|
||||
|
||||
//Get x_element index.
|
||||
$.each(headers, function(index, value) {
|
||||
if (value.cell == x_element) {
|
||||
h_index = index;
|
||||
}
|
||||
});
|
||||
|
||||
$.each( results, function (i, value) {
|
||||
var cells = value.cells;
|
||||
$.each( cells, function(index, value) {
|
||||
if (index == h_index) {
|
||||
x_values.push(value.cell);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return x_values;
|
||||
|
||||
}
|
||||
|
||||
function build_group(y_elements, y_groups) {
|
||||
var groups_hash = {};
|
||||
var groups = [];
|
||||
|
||||
$.each(y_groups, function(index, value) {
|
||||
var related_y = y_elements.shift();
|
||||
if (!$.isArray(groups_hash[value])) {
|
||||
groups_hash[value] = [];
|
||||
}
|
||||
groups_hash[value].push(related_y);
|
||||
});
|
||||
|
||||
$.each(groups_hash, function(key, value) {
|
||||
if (value.length !== 0) {
|
||||
groups.push(value);
|
||||
}
|
||||
});
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
function build_columns(headers, results, x_element, y_elements) {
|
||||
var x_index;
|
||||
var header_index = [];
|
||||
var y_values = {};
|
||||
|
||||
// Keep order of headers using array index.
|
||||
$.each( headers, function(index, value) {
|
||||
if (value.cell == x_element) {
|
||||
x_index = index;
|
||||
}
|
||||
header_index.push(value.cell)
|
||||
});
|
||||
|
||||
$.each( y_elements, function(index, element) {
|
||||
y_values[element] = [element];
|
||||
});
|
||||
|
||||
$.each( results, function (i, value) {
|
||||
var cells = value.cells;
|
||||
$.each( cells, function(index, value) {
|
||||
if (index != x_index) {
|
||||
y_values[header_index[index]].push(value.cell);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var columns = [];
|
||||
$.each( y_values, function(key, value) {
|
||||
columns.push(value);
|
||||
});
|
||||
|
||||
return columns;
|
||||
}
|
|
@ -693,6 +693,7 @@ elsif ($phase eq 'Run this report'){
|
|||
$notes = $report->notes;
|
||||
|
||||
my @rows = ();
|
||||
my @allrows = ();
|
||||
# if we have at least 1 parameter, and it's not filled, then don't execute but ask for parameters
|
||||
if ($sql =~ /<</ && !@sql_params) {
|
||||
# split on ??. Each odd (2,4,6,...) entry should be a parameter to fill
|
||||
|
@ -809,6 +810,7 @@ elsif ($phase eq 'Run this report'){
|
|||
} else {
|
||||
my $sql = get_prepped_report( $sql, \@param_names, \@sql_params);
|
||||
my ( $sth, $errors ) = execute_query( $sql, $offset, $limit, undef, $report_id );
|
||||
my ($sth2, $errors2) = execute_query($sql);
|
||||
my $total = nb_rows($sql) || 0;
|
||||
unless ($sth) {
|
||||
die "execute_query failed to return sth for report $report_id: $sql";
|
||||
|
@ -819,6 +821,10 @@ elsif ($phase eq 'Run this report'){
|
|||
my @cells = map { +{ cell => $_ } } @$row;
|
||||
push @rows, { cells => \@cells };
|
||||
}
|
||||
while (my $row = $sth2->fetchrow_arrayref()) {
|
||||
my @cells = map { +{ cell => $_ } } @$row;
|
||||
push @allrows, { cells => \@cells };
|
||||
}
|
||||
}
|
||||
|
||||
my $totpages = int($total/$limit) + (($total % $limit) > 0 ? 1 : 0);
|
||||
|
@ -828,6 +834,7 @@ elsif ($phase eq 'Run this report'){
|
|||
}
|
||||
$template->param(
|
||||
'results' => \@rows,
|
||||
'allresults' => \@allrows,
|
||||
'sql' => $sql,
|
||||
original_sql => $original_sql,
|
||||
'id' => $report_id,
|
||||
|
|
Loading…
Reference in a new issue