simple_drilldown 0.6.4 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/views/drilldown/_excel_record_list.builder +5 -2
- data/app/views/drilldown/_excel_row.builder +6 -1
- data/app/views/drilldown/_excel_summary_row.builder +5 -1
- data/app/views/drilldown/_export_links.html.erb +2 -0
- data/app/views/drilldown/_record_list.html.erb +2 -2
- data/app/views/drilldown/data_1.builder +6 -2
- data/app/views/drilldown/data_2.builder +21 -9
- data/app/views/drilldown/data_3.builder +34 -11
- data/app/views/drilldown/excel_export.builder +4 -2
- data/app/views/drilldown/{excel_export_transactions.builder → excel_export_records.builder} +6 -6
- data/app/views/drilldown/index.html.erb +25 -33
- data/app/views/drilldown/print.html.erb +7 -4
- data/lib/generators/drilldown_controller/drilldown_controller_generator.rb +1 -1
- data/lib/simple_drilldown/controller.rb +47 -44
- data/lib/simple_drilldown/helper.rb +44 -17
- data/lib/simple_drilldown/routing.rb +6 -4
- data/lib/simple_drilldown/search.rb +8 -12
- data/lib/simple_drilldown/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b9e45eda9e3936d570de7055da2f5ec4eea29f3bfc6a8acc7a7134d364e2343
|
4
|
+
data.tar.gz: e4738f7b4a2bb699724c34b3fcf764de181c56bdfb015f9274a048e8b630a363
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b3eb61535dcd5068e5353f5076c29fb1632aaa252f4bbb61d1644295c423db4f063f12a0417f3495f3b6dde3c01501351b1052af3dca04b1d43b59320e74e33c
|
7
|
+
data.tar.gz: 9f424d5a153153886d7f2732d1dbeeb7f141095f9fc991e4b32f1a09b4e4dee32de54564b67101f74a9d31127627e37a80ebd514e24a5b0e2f60a22c236cb6d1
|
@@ -2,6 +2,9 @@
|
|
2
2
|
|
3
3
|
xml << render(partial: '/drilldown/excel_row_header')
|
4
4
|
|
5
|
-
result[:
|
6
|
-
xml << render(
|
5
|
+
result[:records].each do |t|
|
6
|
+
xml << render(
|
7
|
+
partial: '/drilldown/excel_row',
|
8
|
+
locals: { transaction: t, previous_transaction: nil, errors: [], error_row: false, meter1_errors: false }
|
9
|
+
)
|
7
10
|
end
|
@@ -6,7 +6,12 @@ xml.Row do
|
|
6
6
|
|
7
7
|
@search.fields.each_with_index do |field, i|
|
8
8
|
if field == 'time'
|
9
|
-
value = (
|
9
|
+
value = ((
|
10
|
+
if transaction.respond_to?(:completed_at)
|
11
|
+
transaction.completed_at
|
12
|
+
else
|
13
|
+
transaction.created_at
|
14
|
+
end)).localtime.strftime('%Y-%m-%d %H:%M')
|
10
15
|
else
|
11
16
|
value = if @transaction_fields_map[field.to_sym][:attr_method]
|
12
17
|
@transaction_fields_map[field.to_sym][:attr_method].call(transaction)
|
@@ -9,7 +9,11 @@ xml.Row do
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
if dimension > 0
|
12
|
-
xml.Cell('ss:StyleID' => 'Outer',
|
12
|
+
xml.Cell('ss:StyleID' => 'Outer',
|
13
|
+
'ss:Index' => dimension.to_s) do
|
14
|
+
xml.Data value_label(dimension - 1, result[:value]),
|
15
|
+
'ss:Type' => 'String'
|
16
|
+
end
|
13
17
|
end
|
14
18
|
|
15
19
|
xml.Cell('ss:StyleID' => 'Outer') { xml.Data result[:count].inspect, 'ss:Type' => 'Number' }
|
@@ -0,0 +1,2 @@
|
|
1
|
+
<%= link_to 'Excel', @search.url_options.merge(action: :excel_export) %> |
|
2
|
+
<%= link_to 'HTML', @search.url_options.merge(action: :html_export), data_popup: ['Elections', 'toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes, width=1024px'] %>
|
@@ -1,9 +1,9 @@
|
|
1
|
-
<% unless result[:
|
1
|
+
<% unless result[:records].empty? %>
|
2
2
|
<tr>
|
3
3
|
<td colspan="<%= controller.c_summary_fields.size + 1 %>">
|
4
4
|
<table class="table table-condensed table-bordered" style="padding-bottom: 10px;">
|
5
5
|
<%= render :partial => '/drilldown/row_header' %>
|
6
|
-
<% result[:
|
6
|
+
<% result[:records].each do |t| %>
|
7
7
|
<%= render :partial => '/drilldown/row', :locals => { :transaction => t, :previous_transaction => nil, :errors => [], :error_row => false, :meter1_errors => false } %>
|
8
8
|
<% end %>
|
9
9
|
</table>
|
@@ -4,8 +4,12 @@ xml.chart(xAxisName: (@dimensions[0][:pretty_name] || 'Elections').gsub("'", '')
|
|
4
4
|
showValues: '1', caption: caption, subcaption: subcaption,
|
5
5
|
yAxisName: "Election #{t(@search.select_value.downcase)}", numberSuffix: '') do
|
6
6
|
@result[:rows].each do |res|
|
7
|
-
xml.set
|
7
|
+
xml.set name: @dimensions[0][:label_method] ? @dimensions[0][:label_method].call(res[:value]) : res[:value],
|
8
8
|
value: res[@search.select_value.downcase.to_sym],
|
9
|
-
link: @dimensions[0][:url_param_name]
|
9
|
+
link: if @dimensions[0][:url_param_name]
|
10
|
+
CGI.escape(url_for(@search.drill_down(@dimensions, res[:value]).url_options))
|
11
|
+
else
|
12
|
+
''
|
13
|
+
end
|
10
14
|
end
|
11
15
|
end
|
@@ -1,23 +1,35 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
xml.chart
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
xml.chart(
|
4
|
+
xAxisName: (@dimensions[0][:pretty_name] || 'Elections').gsub("'", ''), palette: '2',
|
5
|
+
caption: caption, subcaption: subcaption,
|
6
|
+
showNames: '1',
|
7
|
+
showValues: @result[:rows].size > 15 || @result[:rows][0] && @result[:rows][0][:rows].size > 4 ? 0 : 1,
|
8
|
+
decimals: '0',
|
9
|
+
numberPrefix: '', clustered: '0', exeTime: '1.5', showPlotBorder: '0', zGapPlot: '30',
|
10
|
+
zDepth: '90', divLineEffect: 'emboss', startAngX: '10', endAngX: '18', startAngY: '-10',
|
11
|
+
numberSuffix: '', zAxisName: 'Z Axis',
|
12
|
+
yAxisName: "Transaction #{t(@search.select_value.downcase)}", endAngY: '-40'
|
13
|
+
) do
|
9
14
|
unless @result[:rows].empty?
|
10
15
|
xml.categories do
|
11
16
|
@result[:rows].each do |result|
|
12
|
-
|
17
|
+
label_method = @dimensions[0][:label_method]
|
18
|
+
xml.category label: label_method ? label_method.call(result[:value]) : result[:value]
|
13
19
|
end
|
14
20
|
end
|
15
21
|
|
16
22
|
@result[:rows][0][:rows].reverse.each_with_index do |result, i|
|
17
|
-
|
23
|
+
name = if @dimensions[1][:label_method]
|
24
|
+
@dimensions[1][:label_method].call(result[:value])
|
25
|
+
else
|
26
|
+
result[:value]
|
27
|
+
end
|
28
|
+
xml.dataset seriesName: name do
|
18
29
|
@result[:rows].each do |res|
|
19
30
|
value = res[:rows].reverse[i][:value]
|
20
|
-
|
31
|
+
label_method = @dimensions[0][:label_method]
|
32
|
+
xml.set(label: (label_method ? label_method.call(res[:value]) : "#{res[:value]}, #{value}"),
|
21
33
|
value: res[:rows].reverse[i][@search.select_value.downcase.to_sym],
|
22
34
|
link: CGI.escape(url_for(@search.drill_down(@dimensions, res[:value], value).url_options)))
|
23
35
|
end
|
@@ -1,25 +1,48 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
xml.chart
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
xml.chart(
|
4
|
+
xAxisName: (@dimensions[0][:pretty_name] || 'Elections').gsub("'", ''), palette: '2',
|
5
|
+
caption: caption, subcaption: subcaption,
|
6
|
+
showNames: '1',
|
7
|
+
showValues:
|
8
|
+
@result[:rows].size > 15 || @result[:rows][0] && @result[:rows][0][:rows].size > 4 ? 0 : 1,
|
9
|
+
decimals: '0',
|
10
|
+
numberPrefix: '', clustered: '0', exeTime: '1.5', showPlotBorder: '0', zGapPlot: '30',
|
11
|
+
zDepth: '90', divLineEffect: 'emboss', startAngX: '10', endAngX: '18', startAngY: '-10',
|
12
|
+
numberSuffix: '', zAxisName: 'Z Axis',
|
13
|
+
yAxisName: "Transaction #{t(@search.select_value.downcase)}", endAngY: '-40'
|
14
|
+
) do
|
9
15
|
unless @result[:rows].empty?
|
10
16
|
xml.categories do
|
11
17
|
@result[:rows].each do |result|
|
12
|
-
xml.category label:
|
18
|
+
xml.category label: if @dimensions[0][:label_method]
|
19
|
+
@dimensions[0][:label_method].call(result[:value])
|
20
|
+
else
|
21
|
+
result[:value]
|
22
|
+
end
|
13
23
|
end
|
14
24
|
end
|
15
25
|
|
16
26
|
@result[:rows][0][:rows].reverse.each_with_index do |result, i|
|
17
|
-
|
27
|
+
series_name =
|
28
|
+
if @dimensions[1][:label_method]
|
29
|
+
@dimensions[1][:label_method].call(result[:value])
|
30
|
+
else
|
31
|
+
result[:value]
|
32
|
+
end
|
33
|
+
xml.dataset seriesName: series_name do
|
18
34
|
@result[:rows].each do |res|
|
19
35
|
value = res[:rows].reverse[i][:value]
|
20
|
-
xml.set(
|
21
|
-
|
22
|
-
|
36
|
+
xml.set(
|
37
|
+
label:
|
38
|
+
if @dimensions[0][:label_method]
|
39
|
+
@dimensions[0][:label_method].call(res[:value])
|
40
|
+
else
|
41
|
+
"#{res[:value]}, #{value}"
|
42
|
+
end,
|
43
|
+
value: res[:rows].reverse[i][@search.select_value.downcase.to_sym],
|
44
|
+
link: CGI.escape(url_for(@search.drill_down(@dimensions, res[:value], value).url_options))
|
45
|
+
)
|
23
46
|
end
|
24
47
|
end
|
25
48
|
end
|
@@ -15,12 +15,14 @@ xml.Workbook(
|
|
15
15
|
xml.Worksheet 'ss:Name' => 'Transaction Summary' do
|
16
16
|
xml.Table do
|
17
17
|
xml.Row 'ss:Height' => '18.75' do
|
18
|
-
xml.Cell 'ss:MergeAcross' => @search.list ? @search.fields.size - 1 : @dimensions.size + 2,
|
18
|
+
xml.Cell 'ss:MergeAcross' => @search.list ? @search.fields.size - 1 : @dimensions.size + 2,
|
19
|
+
'ss:StyleID' => 'MainTitle' do
|
19
20
|
xml.Data caption, 'ss:Type' => 'String'
|
20
21
|
end
|
21
22
|
end
|
22
23
|
xml.Row 'ss:Height' => '15.75' do
|
23
|
-
xml.Cell 'ss:MergeAcross' => @search.list ? @search.fields.size - 1 : @dimensions.size + 2,
|
24
|
+
xml.Cell 'ss:MergeAcross' => @search.list ? @search.fields.size - 1 : @dimensions.size + 2,
|
25
|
+
'ss:StyleID' => 'SubTitle' do
|
24
26
|
xml.Data subcaption, 'ss:Type' => 'String'
|
25
27
|
end
|
26
28
|
end
|
@@ -10,9 +10,9 @@ xml.Workbook(
|
|
10
10
|
'xmlns:ss' => 'urn:schemas-microsoft-com:office:spreadsheet',
|
11
11
|
'xmlns:html' => 'http://www.w3.org/TR/REC-html40'
|
12
12
|
) do
|
13
|
-
xml << render(partial: '/
|
13
|
+
xml << render(partial: '/drilldown/excel_styles')
|
14
14
|
|
15
|
-
xml.Worksheet 'ss:Name' => '
|
15
|
+
xml.Worksheet 'ss:Name' => 'Drilldown' do
|
16
16
|
xml.Table do
|
17
17
|
xml.Row 'ss:Height' => '18.75' do
|
18
18
|
xml.Cell 'ss:MergeAcross' => '35', 'ss:StyleID' => 'MainTitle' do
|
@@ -29,20 +29,20 @@ xml.Workbook(
|
|
29
29
|
@transaction_fields.each do |field|
|
30
30
|
if field == 'time'
|
31
31
|
xml.Cell do
|
32
|
-
xml.Data (
|
32
|
+
xml.Data (t :short_date).to_s, 'ss:Type' => 'String'
|
33
33
|
end
|
34
34
|
xml.Cell do
|
35
|
-
xml.Data (
|
35
|
+
xml.Data (t :time).to_s, 'ss:Type' => 'String'
|
36
36
|
end
|
37
37
|
else
|
38
38
|
xml.Cell do
|
39
|
-
xml.Data (
|
39
|
+
xml.Data (t field).to_s, 'ss:Type' => 'String'
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
-
@
|
45
|
+
@records.each do |transaction|
|
46
46
|
xml.Row do
|
47
47
|
@transaction_fields.each do |field|
|
48
48
|
field_map = controller.c_fields[field.to_sym]
|
@@ -13,25 +13,25 @@
|
|
13
13
|
}
|
14
14
|
</style>
|
15
15
|
|
16
|
-
<%= form_for @search, :
|
16
|
+
<%= form_for @search, html: { id: 'edit_search_SEARCH', method: :get, class: :search, style: 'background: inherit', onsubmit: 'return this.submit()' }, url: {} do |form| %>
|
17
17
|
<div class="row">
|
18
18
|
<div class="col-md-3" valign="top">
|
19
19
|
<ul class="nav nav-tabs">
|
20
|
-
<li class="
|
21
|
-
<a
|
22
|
-
<li><a
|
20
|
+
<li class="nav-item">
|
21
|
+
<a id="filter-tab" class="nav-link active" data-target="#filter" data-toggle="tab"><%= t :filter %></a></li>
|
22
|
+
<li><a id="fields-tab" class="nav-link" data-target="#fields" data-toggle="tab"><%= t :fields %></a>
|
23
23
|
</li>
|
24
24
|
</ul>
|
25
25
|
|
26
26
|
<!-- Tab panes -->
|
27
27
|
<div class="tab-content">
|
28
28
|
<div class="tab-pane active" id="filter">
|
29
|
-
<%= render
|
30
|
-
<%= render
|
29
|
+
<%= render '/drilldown/tab_buttons', form: form %>
|
30
|
+
<%= render '/drilldown/filter', form: form %>
|
31
31
|
</div>
|
32
32
|
<div class="tab-pane" id="fields">
|
33
|
-
<%= render
|
34
|
-
<%= render
|
33
|
+
<%= render '/drilldown/tab_buttons', form: form %>
|
34
|
+
<%= render '/drilldown/fields', form: form %>
|
35
35
|
</div>
|
36
36
|
</div>
|
37
37
|
|
@@ -39,20 +39,16 @@
|
|
39
39
|
<div class="col-md-9">
|
40
40
|
<div class="row" valign="top">
|
41
41
|
<div class="col-md-12">
|
42
|
-
<%= render
|
43
|
-
<br/>
|
42
|
+
<%= render '/drilldown/chart', form: form %>
|
44
43
|
</div>
|
45
44
|
</div>
|
46
45
|
|
47
46
|
<div class="row">
|
48
47
|
<div class="col-md-12" valign="top">
|
49
48
|
<div style="float: right; clear: both;">
|
50
|
-
<%=
|
51
|
-
<%= link_to 'HTML', @search.url_options.merge(action: :html_export), :data_popup => ['Elections', 'toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes, width=1024px'] %>
|
49
|
+
<%= render '/drilldown/export_links' %>
|
52
50
|
</div>
|
53
|
-
|
54
|
-
|
55
|
-
<%= render :partial => '/drilldown/summary_table' %>
|
51
|
+
<%= render '/drilldown/summary_table' %>
|
56
52
|
</div>
|
57
53
|
</div>
|
58
54
|
</div>
|
@@ -60,16 +56,16 @@
|
|
60
56
|
|
61
57
|
<% end %> <!-- END FORM -->
|
62
58
|
|
63
|
-
<%=javascript_tag do %>
|
64
|
-
form = document.getElementById("edit_search_SEARCH");
|
65
|
-
form.submit = function() {
|
66
|
-
elements = form.elements;
|
67
|
-
params =
|
68
|
-
for (
|
69
|
-
if (el.type
|
59
|
+
<%= javascript_tag do %>
|
60
|
+
form = document.getElementById("edit_search_SEARCH");
|
61
|
+
form.submit = function() {
|
62
|
+
let elements = form.elements;
|
63
|
+
let params = [];
|
64
|
+
for (let el, i = 0; (el = elements[i] ); i++) {
|
65
|
+
if (el.name === '' || (el.type === "text" && el.value === "")) {
|
70
66
|
continue;
|
71
67
|
}
|
72
|
-
if (el.type
|
68
|
+
if (el.type === "select-multiple") {
|
73
69
|
if (el.selectedIndex > 0) {
|
74
70
|
for (var j = 0; j < el.options.length; j++) {
|
75
71
|
// Ignore "All" and unselected options
|
@@ -80,28 +76,24 @@ form.submit = function() {
|
|
80
76
|
}
|
81
77
|
continue;
|
82
78
|
}
|
83
|
-
if (el.type
|
79
|
+
if (el.type === "select-one" && el.selectedIndex === 0) {
|
84
80
|
continue;
|
85
81
|
}
|
86
|
-
if (el.type
|
82
|
+
if (el.type === "checkbox" && el.checked !== true) {
|
87
83
|
continue;
|
88
84
|
}
|
89
|
-
if (el.type
|
85
|
+
if (el.type === "radio" && (el.checked !== true || el.value === 'NONE')) {
|
90
86
|
continue;
|
91
87
|
}
|
92
|
-
if (el.type
|
88
|
+
if (el.type === "hidden" && (el.value === "0" || el.value === "")) {
|
93
89
|
continue;
|
94
90
|
}
|
95
|
-
if (el.type
|
91
|
+
if (el.type === "submit") {
|
96
92
|
continue;
|
97
93
|
}
|
98
94
|
params.push("" + el.name + "=" + encodeURIComponent(el.value));
|
99
95
|
}
|
100
96
|
location = form.action + "?" + params.join('&');
|
101
97
|
return false;
|
102
|
-
};
|
103
|
-
|
104
|
-
$(document).ready(function () {
|
105
|
-
$('[data-behaviour~=datepicker]').datepicker({format: "yyyy-mm-dd"});
|
106
|
-
})
|
98
|
+
};
|
107
99
|
<% end %>
|
@@ -1,12 +1,15 @@
|
|
1
1
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
2
|
-
|
2
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
3
3
|
|
4
4
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
5
|
-
<%=
|
6
|
-
<%= stylesheet_link_tag 'drilldown' %>
|
5
|
+
<%= stylesheet_link_tag 'application' %>
|
7
6
|
<body>
|
8
7
|
<style type="text/css">
|
9
|
-
|
8
|
+
@media print {
|
9
|
+
#print_link {
|
10
|
+
display: none
|
11
|
+
}
|
12
|
+
}
|
10
13
|
</style>
|
11
14
|
<div class="container">
|
12
15
|
<div id="print_link" class="pull-right">
|
@@ -6,6 +6,6 @@ class DrilldownControllerGenerator < Rails::Generators::NamedBase
|
|
6
6
|
def copy_drilldown_controller_file
|
7
7
|
template 'drilldown_controller.rb.erb', "app/controllers/#{file_name}_drilldown_controller.rb"
|
8
8
|
template 'drilldown_controller_test.rb.erb', "test/controllers/#{file_name}_drilldown_controller_test.rb"
|
9
|
-
route "draw_drilldown :#{singular_name}
|
9
|
+
route "draw_drilldown :#{singular_name}"
|
10
10
|
end
|
11
11
|
end
|
@@ -33,6 +33,7 @@ module SimpleDrilldown
|
|
33
33
|
begin
|
34
34
|
base.c_target_class = base.name.chomp('Controller').constantize
|
35
35
|
rescue NameError
|
36
|
+
# No default target class found
|
36
37
|
end
|
37
38
|
end
|
38
39
|
end
|
@@ -101,7 +102,9 @@ module SimpleDrilldown
|
|
101
102
|
raise "Unexpected options: #{options.inspect}" if options.present?
|
102
103
|
|
103
104
|
queries.each do |query_opts|
|
104
|
-
|
105
|
+
unless (query_opts.keys - %i[select includes where]).empty?
|
106
|
+
raise "Unknown options: #{query_opts.keys.inspect}"
|
107
|
+
end
|
105
108
|
end
|
106
109
|
|
107
110
|
c_dimension_defs[name.to_s] = {
|
@@ -125,7 +128,8 @@ module SimpleDrilldown
|
|
125
128
|
pretty_name: I18n.t(name, default: :"activerecord.models.#{name}"),
|
126
129
|
queries: queries,
|
127
130
|
reverse: reverse,
|
128
|
-
select_expression:
|
131
|
+
select_expression:
|
132
|
+
queries.size == 1 ? queries[0][:select] : "COALESCE(#{queries.map { |q| q[:select] }.join(',')})",
|
129
133
|
row_class: row_class,
|
130
134
|
url_param_name: name.to_s
|
131
135
|
}
|
@@ -182,7 +186,7 @@ module SimpleDrilldown
|
|
182
186
|
dimension_def = c_dimension_defs[field]
|
183
187
|
raise "Unknown filter field: #{field.inspect}" if dimension_def.nil?
|
184
188
|
|
185
|
-
values =
|
189
|
+
values = Array(values)
|
186
190
|
if dimension_def[:interval]
|
187
191
|
values *= 2 if values.size == 1
|
188
192
|
raise "Need 2 values for interval filter: #{values.inspect}" if values.size != 2
|
@@ -237,9 +241,9 @@ module SimpleDrilldown
|
|
237
241
|
when Hash
|
238
242
|
sql = +''
|
239
243
|
include.each do |parent, child|
|
240
|
-
sql <<
|
244
|
+
sql << " #{make_join(joins, model, parent)}"
|
241
245
|
ass = model.to_s.camelize.constantize.reflect_on_association parent
|
242
|
-
sql <<
|
246
|
+
sql << " #{make_join(joins, parent, child, ass.class_name.constantize)}"
|
243
247
|
end
|
244
248
|
sql
|
245
249
|
when Symbol
|
@@ -373,8 +377,7 @@ module SimpleDrilldown
|
|
373
377
|
selected = @search.filter[dimension_name] || []
|
374
378
|
raise "Unknown dimension #{dimension_name.inspect}: #{c_dimension_defs.keys.inspect}" unless dimension
|
375
379
|
|
376
|
-
choices = [[t(:all), nil]] +
|
377
|
-
(dimension[:legal_values]&.call(@search)&.map { |o| o.is_a?(Array) ? o[0..1].map(&:to_s) : o.to_s } || [])
|
380
|
+
choices = [[t(:all), nil]] + (legal_values_for_dimension(dimension) || [])
|
378
381
|
choices_html = choices.map do |c|
|
379
382
|
%(<option value="#{c[1]}"#{' SELECTED' if selected.include?(c[1])}>#{c[0]}</option>)
|
380
383
|
end.join("\n")
|
@@ -383,36 +386,37 @@ module SimpleDrilldown
|
|
383
386
|
|
384
387
|
def html_export
|
385
388
|
index(false)
|
386
|
-
render template: '/drilldown/html_export', layout: 'print'
|
389
|
+
render template: '/drilldown/html_export', layout: '../drilldown/print'
|
387
390
|
end
|
388
391
|
|
389
392
|
def excel_export
|
390
393
|
index(false)
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
394
|
+
set_excel_headers
|
395
|
+
if params.dig(:search, :list) == '1'
|
396
|
+
@records = get_records(@result)
|
397
|
+
render template: '/drilldown/excel_export_records', layout: false
|
398
|
+
else
|
399
|
+
render template: '/drilldown/excel_export', layout: false
|
400
|
+
end
|
395
401
|
end
|
396
402
|
|
397
|
-
def
|
403
|
+
def excel_export_records
|
404
|
+
params[:search] ||= {}
|
398
405
|
params[:search][:list] = '1'
|
399
|
-
|
400
|
-
@transactions = get_transactions(@result)
|
401
|
-
headers['Content-Type'] = 'application/vnd.ms-excel'
|
402
|
-
headers['Content-Disposition'] = 'attachment; filename="transactions.xml"'
|
403
|
-
render template: '/drilldown/excel_export_transactions', layout: false
|
406
|
+
excel_export
|
404
407
|
end
|
405
408
|
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
headers['Content-
|
411
|
-
headers['
|
412
|
-
render template: '/drilldown/xml_export', layout: false
|
409
|
+
private
|
410
|
+
|
411
|
+
def set_excel_headers
|
412
|
+
headers['Content-Type'] = 'application/vnd.ms-excel'
|
413
|
+
headers['Content-Disposition'] = %{attachment; filename="#{c_target_class.table_name}.xml"}
|
414
|
+
headers['Cache-Control'] = ''
|
413
415
|
end
|
414
416
|
|
415
|
-
|
417
|
+
def legal_values_for_dimension(dimension)
|
418
|
+
dimension[:legal_values]&.call(@search)&.map { |o| o.is_a?(Array) ? o[0..1].map(&:to_s) : o.to_s }
|
419
|
+
end
|
416
420
|
|
417
421
|
def new_search_object
|
418
422
|
SimpleDrilldown::Search.new(params[:search]&.to_unsafe_h, c_default_fields, c_default_select_value)
|
@@ -495,7 +499,8 @@ module SimpleDrilldown
|
|
495
499
|
|
496
500
|
result_rows = []
|
497
501
|
loop do
|
498
|
-
sub_result = result_from_rows(rows, row_index, dimension + 1,
|
502
|
+
sub_result = result_from_rows(rows, row_index, dimension + 1,
|
503
|
+
values + [rows[row_index]["value#{dimension + 1}"]])
|
499
504
|
break if sub_result.nil?
|
500
505
|
|
501
506
|
result_rows << sub_result
|
@@ -517,23 +522,20 @@ module SimpleDrilldown
|
|
517
522
|
end
|
518
523
|
|
519
524
|
def populate_list(conditions, includes, result, values)
|
520
|
-
if result[:rows]
|
521
|
-
|
522
|
-
end
|
525
|
+
return result[:rows].each { |r| populate_list(conditions, includes, r, values + [r[:value]]) } if result[:rows]
|
526
|
+
|
523
527
|
list_includes = merge_includes(includes, c_list_includes)
|
524
528
|
@search.fields.each do |field|
|
525
529
|
field_def = c_fields[field.to_sym]
|
526
530
|
raise "Field definition missing for: #{field.inspect}" unless field_def
|
527
531
|
|
528
532
|
field_includes = field_def[:include]
|
529
|
-
if field_includes
|
530
|
-
list_includes = merge_includes(list_includes , field_includes)
|
531
|
-
end
|
533
|
+
list_includes = merge_includes(list_includes, field_includes) if field_includes
|
532
534
|
end
|
533
535
|
if @search.list_change_times
|
534
536
|
@history_fields.each do |f|
|
535
537
|
if @search.fields.include? f
|
536
|
-
list_includes = merge_includes(list_includes, assignment: { order: :"#{f}_changes" }
|
538
|
+
list_includes = merge_includes(list_includes, assignment: { order: :"#{f}_changes" })
|
537
539
|
end
|
538
540
|
end
|
539
541
|
end
|
@@ -541,17 +543,17 @@ module SimpleDrilldown
|
|
541
543
|
list_conditions = list_conditions(conditions, values)
|
542
544
|
base_query = c_target_class.unscoped.where(c_base_condition).joins(joins).order(c_list_order)
|
543
545
|
base_query = base_query.where(list_conditions) if list_conditions
|
544
|
-
result[:
|
546
|
+
result[:records] = base_query.to_a
|
545
547
|
end
|
546
548
|
|
547
549
|
def merge_includes(*args)
|
548
550
|
hash = hash_includes(*args)
|
549
|
-
result = hash.dup.map
|
551
|
+
result = hash.dup.map do |k, v|
|
550
552
|
if v.blank?
|
551
553
|
hash.delete(k)
|
552
554
|
k
|
553
555
|
end
|
554
|
-
|
556
|
+
end.compact
|
555
557
|
result << hash unless hash.blank?
|
556
558
|
case result.size
|
557
559
|
when 0
|
@@ -567,14 +569,15 @@ module SimpleDrilldown
|
|
567
569
|
args.inject({}) do |h, inc|
|
568
570
|
case inc
|
569
571
|
when Array
|
570
|
-
inc.each
|
572
|
+
inc.each do |v|
|
571
573
|
h = hash_includes(h, v)
|
572
|
-
|
574
|
+
end
|
573
575
|
when Hash
|
574
|
-
inc.each
|
576
|
+
inc.each do |k, v|
|
575
577
|
h[k] = merge_includes(h[k], v)
|
576
|
-
|
578
|
+
end
|
577
579
|
when NilClass, FalseClass
|
580
|
+
# Leave as it is
|
578
581
|
when String, Symbol
|
579
582
|
h[inc] ||= []
|
580
583
|
else
|
@@ -594,10 +597,10 @@ module SimpleDrilldown
|
|
594
597
|
[list_conditions_string, *(conditions[1..-1] + values)]
|
595
598
|
end
|
596
599
|
|
597
|
-
def
|
598
|
-
return tree[:
|
600
|
+
def get_records(tree)
|
601
|
+
return tree[:records] if tree[:records]
|
599
602
|
|
600
|
-
tree[:rows].map { |r|
|
603
|
+
tree[:rows].map { |r| get_records(r) }.flatten
|
601
604
|
end
|
602
605
|
|
603
606
|
class ScopeHolder
|
@@ -11,9 +11,8 @@ module SimpleDrilldown
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def caption
|
14
|
-
result = @search.title ||
|
15
|
-
|
16
|
-
result.gsub('$date', [*@search.filter[:calendar_date]].uniq.join(' - '))
|
14
|
+
result = @search.title || caption_txt
|
15
|
+
result.gsub('$date', Array(@search.filter[:calendar_date]).uniq.join(' - '))
|
17
16
|
end
|
18
17
|
|
19
18
|
def subcaption
|
@@ -21,9 +20,15 @@ module SimpleDrilldown
|
|
21
20
|
end
|
22
21
|
|
23
22
|
def summary_row(result, parent_result = nil, dimension = 0, headers = [], new_row = true)
|
24
|
-
html = render(partial: '/drilldown/summary_row', locals: {
|
23
|
+
html = render(partial: '/drilldown/summary_row', locals: {
|
24
|
+
result: result, parent_result: parent_result, new_row: new_row, dimension: dimension,
|
25
|
+
headers: headers, with_results: !result[:rows]
|
26
|
+
})
|
25
27
|
if result[:rows]
|
26
|
-
sub_headers = headers + [{
|
28
|
+
sub_headers = headers + [{
|
29
|
+
value: result[:value],
|
30
|
+
display_row_count: result[:nodes] + result[:row_count] * (@search.list ? 1 : 0)
|
31
|
+
}]
|
27
32
|
significant_rows = result[:rows].reject { |r| r[:row_count].zero? }
|
28
33
|
significant_rows.each_with_index do |r, i|
|
29
34
|
html << summary_row(r, result, dimension + 1, sub_headers, i.positive?)
|
@@ -31,7 +36,12 @@ module SimpleDrilldown
|
|
31
36
|
elsif @search.list
|
32
37
|
html << render(partial: '/drilldown/record_list', locals: { result: result })
|
33
38
|
end
|
34
|
-
|
39
|
+
if dimension < @dimensions.size
|
40
|
+
html << render(partial: '/drilldown/summary_total_row',
|
41
|
+
locals: {
|
42
|
+
result: result, parent_result: parent_result, headers: headers.dup, dimension: dimension
|
43
|
+
})
|
44
|
+
end
|
35
45
|
|
36
46
|
html
|
37
47
|
end
|
@@ -41,25 +51,42 @@ module SimpleDrilldown
|
|
41
51
|
if result[:rows]
|
42
52
|
significant_rows = result[:rows].reject { |r| r[:row_count].zero? }
|
43
53
|
significant_rows.each_with_index do |r, i|
|
44
|
-
sub_headers =
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
54
|
+
sub_headers =
|
55
|
+
if i.zero?
|
56
|
+
if dimension.zero?
|
57
|
+
headers
|
58
|
+
else
|
59
|
+
headers + [{
|
60
|
+
value: result[:value],
|
61
|
+
display_row_count: result[:nodes] + result[:row_count] * (@search.list ? 1 : 0)
|
62
|
+
}]
|
63
|
+
end
|
64
|
+
else
|
65
|
+
[] # [{:value => result[:value], :row_count => result[:row_count]}]
|
66
|
+
end
|
53
67
|
xml << excel_summary_row(r, result, dimension + 1, sub_headers)
|
54
68
|
end
|
55
69
|
else
|
56
|
-
xml << render(partial: '/drilldown/excel_summary_row',
|
70
|
+
xml << render(partial: '/drilldown/excel_summary_row',
|
71
|
+
locals: { result: result, parent_result: parent_result, headers: headers.dup,
|
72
|
+
dimension: dimension })
|
57
73
|
|
58
74
|
xml << render(partial: '/drilldown/excel_record_list', locals: { result: result }) if @search.list
|
59
75
|
end
|
60
76
|
|
61
|
-
|
77
|
+
if dimension < @dimensions.size
|
78
|
+
xml << render(partial: '/drilldown/excel_summary_total_row', locals: {
|
79
|
+
result: result, headers: headers.dup, dimension: dimension
|
80
|
+
})
|
81
|
+
end
|
62
82
|
xml
|
63
83
|
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def caption_txt
|
88
|
+
"#{controller.c_target_class} #{t(@search.select_value.downcase)}" +
|
89
|
+
(@dimensions && @dimensions.any? ? " by #{@dimensions.map { |d| d[:pretty_name] }.join(' and ')}" : '')
|
90
|
+
end
|
64
91
|
end
|
65
92
|
end
|
@@ -3,11 +3,13 @@
|
|
3
3
|
module SimpleDrilldown
|
4
4
|
# Routing helper methods
|
5
5
|
module Routing
|
6
|
-
def draw_drilldown(path, controller =
|
6
|
+
def draw_drilldown(path, controller = nil)
|
7
|
+
path = "#{path}_drilldown" unless /_drilldown$/.match?(path)
|
8
|
+
controller ||= path
|
7
9
|
get "#{path}(.:format)" => "#{controller}#index", as: path
|
8
|
-
scope path do
|
9
|
-
%i[choices excel_export html_export index].each do |action|
|
10
|
-
get "#{action}(/:id)(.:format)", controller: controller, action: action
|
10
|
+
scope path, as: path do
|
11
|
+
%i[choices excel_export excel_export_records html_export index].each do |action|
|
12
|
+
get "#{action}(/:id)(.:format)", controller: controller, action: action, as: action
|
11
13
|
end
|
12
14
|
end
|
13
15
|
end
|
@@ -19,17 +19,9 @@ module SimpleDrilldown
|
|
19
19
|
VOLUME_COMPENSATED = 'VOLUME_COMPENSATED'
|
20
20
|
end
|
21
21
|
|
22
|
-
attr_reader :dimensions
|
23
|
-
|
24
|
-
|
25
|
-
attr_reader :filter
|
26
|
-
attr_accessor :list
|
27
|
-
attr_accessor :percent
|
28
|
-
attr_reader :list_change_times
|
29
|
-
attr_reader :order_by_value
|
30
|
-
attr_reader :select_value
|
31
|
-
attr_reader :title
|
32
|
-
attr_reader :default_fields
|
22
|
+
attr_reader :dimensions, :display_type, :fields, :filter, :list_change_times, :order_by_value,
|
23
|
+
:select_value, :title, :default_fields
|
24
|
+
attr_accessor :list, :percent
|
33
25
|
|
34
26
|
def self.validators_on(_attribute)
|
35
27
|
[]
|
@@ -60,7 +52,7 @@ module SimpleDrilldown
|
|
60
52
|
@dimensions = attributes && attributes[:dimensions] || []
|
61
53
|
@dimensions.delete_if(&:empty?)
|
62
54
|
@filter = attributes && attributes[:filter] ? attributes[:filter] : {}
|
63
|
-
@filter.keys.dup.each { |k| @filter[k] =
|
55
|
+
@filter.keys.dup.each { |k| @filter[k] = Array(@filter[k]) }
|
64
56
|
@filter.each do |_k, v|
|
65
57
|
v.delete('')
|
66
58
|
v.delete('Select Some Options')
|
@@ -108,6 +100,10 @@ module SimpleDrilldown
|
|
108
100
|
'SEARCH'
|
109
101
|
end
|
110
102
|
|
103
|
+
def list?
|
104
|
+
list
|
105
|
+
end
|
106
|
+
|
111
107
|
def drill_down(dimensions, *values)
|
112
108
|
raise 'Too many values' if values.size > self.dimensions.size
|
113
109
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple_drilldown
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Uwe Kubosch
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-10-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chartkick
|
@@ -97,6 +97,7 @@ files:
|
|
97
97
|
- app/views/drilldown/_excel_styles.builder
|
98
98
|
- app/views/drilldown/_excel_summary_row.builder
|
99
99
|
- app/views/drilldown/_excel_summary_total_row.builder
|
100
|
+
- app/views/drilldown/_export_links.html.erb
|
100
101
|
- app/views/drilldown/_field.html.erb
|
101
102
|
- app/views/drilldown/_fields.html.erb
|
102
103
|
- app/views/drilldown/_filter.html.erb
|
@@ -112,7 +113,7 @@ files:
|
|
112
113
|
- app/views/drilldown/data_2.builder
|
113
114
|
- app/views/drilldown/data_3.builder
|
114
115
|
- app/views/drilldown/excel_export.builder
|
115
|
-
- app/views/drilldown/
|
116
|
+
- app/views/drilldown/excel_export_records.builder
|
116
117
|
- app/views/drilldown/html_export.html.erb
|
117
118
|
- app/views/drilldown/index.html.erb
|
118
119
|
- app/views/drilldown/print.html.erb
|
@@ -145,7 +146,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
145
146
|
requirements:
|
146
147
|
- - ">="
|
147
148
|
- !ruby/object:Gem::Version
|
148
|
-
version: '
|
149
|
+
version: '2.5'
|
149
150
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
150
151
|
requirements:
|
151
152
|
- - ">="
|