simple_drilldown 0.3.3 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +9 -6
- data/app/views/drilldown/_chart.html.erb +62 -0
- data/app/views/drilldown/_field.html.erb +0 -1
- data/app/views/drilldown/_filter.html.erb +4 -14
- data/app/views/drilldown/_record_list.html.erb +3 -3
- data/app/views/drilldown/_row.html.erb +9 -9
- data/app/views/drilldown/_summary_row.html.erb +12 -12
- data/app/views/drilldown/_summary_table.html.erb +2 -2
- data/app/views/drilldown/excel_export_transactions.builder +1 -1
- data/lib/generators/drilldown_controller/USAGE +1 -0
- data/lib/generators/drilldown_controller/drilldown_controller_generator.rb +2 -1
- data/lib/generators/drilldown_controller/templates/drilldown_controller.rb.erb +22 -12
- data/lib/generators/drilldown_controller/templates/drilldown_controller_test.rb.erb +15 -0
- data/lib/simple_drilldown/{drilldown_controller.rb → controller.rb} +148 -93
- data/lib/simple_drilldown/drilldown_helper.rb +31 -33
- data/lib/simple_drilldown/engine.rb +6 -0
- data/lib/simple_drilldown/routing.rb +15 -0
- data/lib/simple_drilldown/version.rb +1 -1
- metadata +9 -7
- data/app/views/drilldown/_chart.html.slim +0 -52
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a69810eb60aa499744a6989bad20efed263b05fc51dfcb094f151494deacbad
|
4
|
+
data.tar.gz: e3402d01f9a8a19683c6c4095fa47725eede9dda5434ff2dd9a43cb5d5e75643
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7701b13e4ee048dd707b9e5a787e2081932ad301cb62eb028e770033664a6d7696267fd2a409a79a540db73a06026305b2bd2eee597fdd8196c7568db161d2f6
|
7
|
+
data.tar.gz: 5a9a820ecee0516f76bebb0a3ce64325a80e0e3f71f4855b2529ab07b451cf87db2148544114343f40d5f35e624bf5bac8c614ca600642ca8127b62f6ffc072c
|
data/README.md
CHANGED
@@ -4,9 +4,9 @@
|
|
4
4
|
<img align="right" src="https://travis-ci.org/DatekWireless/simple_drilldown.svg?branch=master" alt="Build Status">
|
5
5
|
</a>
|
6
6
|
|
7
|
-
simple_drilldown offers a simple way to define axis to filter and group records
|
7
|
+
`simple_drilldown` offers a simple way to define axis to filter and group records
|
8
8
|
for analysis. The result is a record count for the selected filter and
|
9
|
-
distribution and the option to list the actual records.
|
9
|
+
distribution and the option to list and export the actual records.
|
10
10
|
|
11
11
|
## Usage
|
12
12
|
|
@@ -16,6 +16,10 @@ For a given schema:
|
|
16
16
|
|
17
17
|
```ruby
|
18
18
|
ActiveRecord::Schema.define(version: 20141204155251) do
|
19
|
+
create_table "users" do |t|
|
20
|
+
t.string "name", limit: 16, null: false
|
21
|
+
end
|
22
|
+
|
19
23
|
create_table "posts" do |t|
|
20
24
|
t.string "title", null: false
|
21
25
|
t.text "body", null: false
|
@@ -25,12 +29,9 @@ ActiveRecord::Schema.define(version: 20141204155251) do
|
|
25
29
|
t.datetime "updated_at", null: false
|
26
30
|
end
|
27
31
|
|
28
|
-
create_table "users" do |t|
|
29
|
-
t.string "name", limit: 16, null: false
|
30
|
-
end
|
31
|
-
|
32
32
|
create_table "comments" do |t|
|
33
33
|
t.integer "post_id", null: false
|
34
|
+
t.integer "user_id", null: false
|
34
35
|
t.string "title", null: false
|
35
36
|
t.text "body", null: false
|
36
37
|
t.integer "rating", null: false
|
@@ -65,6 +66,8 @@ end
|
|
65
66
|
Create a new controller to focus on posts. Each drilldown controller focuses on
|
66
67
|
one main entity.
|
67
68
|
|
69
|
+
bin/rails g drilldown_controller User
|
70
|
+
|
68
71
|
```ruby
|
69
72
|
class PostsDrilldownController < DrilldownController
|
70
73
|
|
@@ -0,0 +1,62 @@
|
|
1
|
+
<%
|
2
|
+
data =
|
3
|
+
case @dimensions.size
|
4
|
+
when 0
|
5
|
+
{ @result[:value] => @result[:count] }
|
6
|
+
when 1
|
7
|
+
@result[:rows].map { |r| [@dimensions[0][:label_method] ? @dimensions[0][:label_method].call(r[:value]) : r[:value], r[:count]] }
|
8
|
+
when 2
|
9
|
+
@result[:rows].map do |r|
|
10
|
+
{
|
11
|
+
name: r[:value],
|
12
|
+
data: r[:rows].map { |r2| [r2[:value], r2[:count]] }
|
13
|
+
}
|
14
|
+
end
|
15
|
+
when 3
|
16
|
+
end
|
17
|
+
%>
|
18
|
+
|
19
|
+
<%
|
20
|
+
case @search.display_type
|
21
|
+
when SimpleDrilldown::Search::DisplayType::PIE
|
22
|
+
%>
|
23
|
+
<%= pie_chart data, height: '24rem' %>
|
24
|
+
<% when SimpleDrilldown::Search::DisplayType::BAR %>
|
25
|
+
<%= column_chart data, height: '24rem' %>
|
26
|
+
<% when SimpleDrilldown::Search::DisplayType::LINE %>
|
27
|
+
<%= line_chart data, height: '24rem' %>
|
28
|
+
<% else %>
|
29
|
+
<div id="drilldown_area">
|
30
|
+
<h2><%= caption %></h2>
|
31
|
+
<h3><%= subcaption %></h3>
|
32
|
+
<br/>
|
33
|
+
</div>
|
34
|
+
<% end %>
|
35
|
+
|
36
|
+
<div id="drilldown_search_area" style="margin-left: auto; margin-right: auto; text-align: center">
|
37
|
+
<% (0..2).each do |i|
|
38
|
+
options = [['', '']]
|
39
|
+
options << [@dimensions[i][:pretty_name], @dimensions[i][:url_param_name]] if @dimensions[i]
|
40
|
+
options += @remaining_dimensions.keys.map { |name| [controller.c_dimension_defs[name][:pretty_name], name] } %>
|
41
|
+
<%= t(i == 0 ? :group_by : :then_by) %>:
|
42
|
+
<%= form.select 'dimensions', options, { :selected => @search.dimensions && @search.dimensions[i] },
|
43
|
+
{ :onChange => 'form.submit()', :name => 'search[dimensions][]', :id => "search_dimensions_#{i}" } %>
|
44
|
+
<% end %>
|
45
|
+
|
46
|
+
<br/>
|
47
|
+
<%= t :chart_type %>
|
48
|
+
<%= form.radio_button 'display_type', SimpleDrilldown::Search::DisplayType::BAR, { :onChange => 'form.submit()' } %>
|
49
|
+
<%= form.label :display_type_bar, t(:bar) %>
|
50
|
+
<%= form.radio_button 'display_type', SimpleDrilldown::Search::DisplayType::PIE, { :disabled => @search.dimensions.size >= 2, :onChange => 'form.submit()' } %>
|
51
|
+
<%= form.label :display_type_pie, t(:pie) %>
|
52
|
+
<%= form.radio_button 'display_type', SimpleDrilldown::Search::DisplayType::LINE, { :onChange => 'form.submit()' } %>
|
53
|
+
<%= form.label :display_type_line, t(:line) %>
|
54
|
+
<%= form.radio_button 'display_type', SimpleDrilldown::Search::DisplayType::NONE, { :onChange => 'form.submit()' } %>
|
55
|
+
<%= form.label :display_type_none, t(:none) %>
|
56
|
+
|
57
|
+
<%= form.check_box :order_by_value, { :onChange => 'form.submit()' } %>
|
58
|
+
<%= form.label :order_by_value, t(:order_by_value) %>
|
59
|
+
|
60
|
+
<%= form.check_box :list, { :onChange => 'form.submit()' } %>
|
61
|
+
<%= form.label :list, t(:list) %>
|
62
|
+
</div>
|
@@ -3,18 +3,8 @@
|
|
3
3
|
<%= form.text_field :title, class: 'form-control' %>
|
4
4
|
</div>
|
5
5
|
|
6
|
-
<%
|
7
|
-
<%
|
8
|
-
|
9
|
-
|
10
|
-
<% ActiveRecord::Base.connection_pool.with_connection do %>
|
11
|
-
<% choices[dimension_name] = [[t(:all), nil]] + (dimension[:legal_values] && dimension[:legal_values].call(@search).map { |o| o.is_a?(Array) ? [o[0].to_s, o[1].to_s] : o.to_s } || []) %>
|
12
|
-
<% end %>
|
13
|
-
<% end %>
|
14
|
-
<% next [t, dimension_name] %>
|
15
|
-
<% end %>
|
16
|
-
<% threads.each do |t, dimension_name| %>
|
17
|
-
<% t.join %>
|
18
|
-
<%= render partial: 'drilldown/field', locals: {choices: choices[dimension_name] || [],
|
19
|
-
form: form, dimension_name: dimension_name} %>
|
6
|
+
<% controller.c_dimension_defs.each do |dimension_name, dimension| %>
|
7
|
+
<% choices = [[t(:all), nil]] + (dimension[:legal_values] && dimension[:legal_values].call(@search).map { |o| o.is_a?(Array) ? [o[0].to_s, o[1].to_s] : o.to_s } || []) %>
|
8
|
+
<%= render partial: 'drilldown/field', locals: { choices: choices || [],
|
9
|
+
form: form, dimension_name: dimension_name } %>
|
20
10
|
<% end %>
|
@@ -1,10 +1,10 @@
|
|
1
1
|
<% unless result[:transactions].empty? %>
|
2
2
|
<tr>
|
3
|
-
<td colspan="
|
3
|
+
<td colspan="<%= controller.c_summary_fields.size + 1 %>">
|
4
4
|
<table class="table table-condensed table-bordered" style="padding-bottom: 10px;">
|
5
|
-
<%=render :partial => '/drilldown/row_header' %>
|
5
|
+
<%= render :partial => '/drilldown/row_header' %>
|
6
6
|
<% result[:transactions].each do |t| %>
|
7
|
-
<%=render :partial => '/drilldown/row', :locals => {:transaction => t, :previous_transaction => nil, :errors => [], :error_row => false, :meter1_errors => false} %>
|
7
|
+
<%= render :partial => '/drilldown/row', :locals => { :transaction => t, :previous_transaction => nil, :errors => [], :error_row => false, :meter1_errors => false } %>
|
8
8
|
<% end %>
|
9
9
|
</table>
|
10
10
|
</td>
|
@@ -1,13 +1,13 @@
|
|
1
1
|
<tr valign="top">
|
2
2
|
<% @search.fields.each do |field| %>
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
<td>
|
4
|
+
<% if field == 'time' %>
|
5
|
+
<%= (transaction.respond_to?(:completed_at) ? transaction.completed_at : transaction.created_at).localtime.strftime('%Y-%m-%d %H:%M') %>
|
6
|
+
<% else %>
|
7
|
+
<% field_def = controller.c_fields[field.to_sym] %>
|
8
|
+
<%= field_def[:attr_method] ? field_def[:attr_method].call(transaction) : transaction.send(field) %>
|
9
|
+
<% end %>
|
10
|
+
</td>
|
11
11
|
<% end %>
|
12
|
-
<td><%=
|
12
|
+
<td><%= link_to t(:show), transaction %></td>
|
13
13
|
</tr>
|
@@ -1,18 +1,18 @@
|
|
1
1
|
<% if new_row -%>
|
2
|
-
|
3
|
-
|
2
|
+
<tr class="<%= cycle("odd", "even", :name => "dim#{dimension}") %>">
|
3
|
+
<% ((dimension + 1)..(@dimensions.size)).each { |i| cycle("odd", "even", :name => "dim#{i}") if current_cycle("dim#{i}") != current_cycle("dim#{dimension}") } -%>
|
4
4
|
<% end -%>
|
5
5
|
<% if dimension > 0 %>
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
<td valign="top" rowspan="<%= result[:nodes] %>">
|
7
|
+
<%= link_to value_label(dimension - 1, result[:value]), @search.drill_down(@dimensions, *[headers[1..-1], result].flatten.map { |h| h[:value] }).url_options %>
|
8
|
+
</td>
|
9
9
|
<% end %>
|
10
10
|
<% if with_results %>
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
11
|
+
<td align="right">
|
12
|
+
<%= result[:count] %>
|
13
|
+
<% if parent_result && @search.percent %>
|
14
|
+
(<%= 100 * result[:count] / parent_result[:count] %>%)
|
15
|
+
<% end %>
|
16
|
+
</td>
|
17
|
+
</tr>
|
18
18
|
<% end %>
|
@@ -3,8 +3,8 @@
|
|
3
3
|
<% @dimensions.each do |d| %>
|
4
4
|
<th><%=h d[:pretty_name]%></th>
|
5
5
|
<% end %>
|
6
|
-
<th><%= t
|
7
|
-
<%=
|
6
|
+
<th><%= t controller.c_target_class.table_name.capitalize %></th>
|
7
|
+
<%= controller.c_summary_fields.map{|l| "<th>#{t(l)}</th>"}.join("\n").html_safe %>
|
8
8
|
</tr>
|
9
9
|
|
10
10
|
<%=summary_row(@result) %>
|
@@ -45,7 +45,7 @@ xml.Workbook(
|
|
45
45
|
@transactions.each do |transaction|
|
46
46
|
xml.Row do
|
47
47
|
@transaction_fields.each do |field|
|
48
|
-
field_map =
|
48
|
+
field_map = controller.c_fields[field.to_sym]
|
49
49
|
if field == 'time'
|
50
50
|
xml.Cell 'ss:StyleID' => 'DateOnlyFormat' do
|
51
51
|
xml.Data transaction.completed_at.gmtime.xmlschema, 'ss:Type' => 'DateTime'
|
@@ -5,6 +5,7 @@ class DrilldownControllerGenerator < Rails::Generators::NamedBase
|
|
5
5
|
|
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}_drilldown"
|
9
10
|
end
|
10
11
|
end
|
@@ -1,14 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
# What fields should be displayed as default when listing actual <%= class_name %> records.
|
5
|
-
default_fields %w[created_at updated_at] # TODO(uwe): Read fields from schema?
|
3
|
+
require 'simple_drilldown/controller'
|
6
4
|
|
5
|
+
class <%= class_name %>DrilldownController < SimpleDrilldown::Controller
|
7
6
|
# The main focus of the drilldown
|
8
|
-
target_class <%= class_name %>
|
7
|
+
# target_class <%= class_name %>
|
8
|
+
|
9
|
+
# `where` clause for the base line
|
10
|
+
# base_condition '1=1'
|
9
11
|
|
10
12
|
# How should we count the reords?
|
11
|
-
select 'count(*) as count'
|
13
|
+
# select 'count(*) as count'
|
14
|
+
|
15
|
+
# When selecting records, what relations should be included for optimization?
|
16
|
+
# Other relations can be included for specific dimensions and fields.
|
17
|
+
# base_includes :user, :comments # TODO(uwe): Read relations from schema?
|
18
|
+
|
19
|
+
# What fields should be displayed as default when listing actual <%= class_name %> records.
|
20
|
+
default_fields %w[created_at updated_at] # TODO(uwe): Read fields from schema?
|
12
21
|
|
13
22
|
# When listing records, what relations should be included for optimization?
|
14
23
|
# list_includes :user, :comments # TODO(uwe): Read relations from schema?
|
@@ -27,14 +36,15 @@ class <%= class_name %>DrilldownController < DrilldownController
|
|
27
36
|
# field :comments, attr_method: ->(post) { post.comments.count }
|
28
37
|
|
29
38
|
dimension :calendar_date, 'DATE(<%= plural_name %>.created_at)', interval: true
|
30
|
-
dimension :day_of_month, "date_part('day', <%= plural_name %>.created_at)"
|
31
|
-
dimension :day_of_week,
|
32
|
-
|
33
|
-
|
34
|
-
dimension :
|
39
|
+
dimension :day_of_month, "date_part('day', <%= plural_name %>.created_at)::int"
|
40
|
+
dimension :day_of_week, <<~SQL, label_method: ->(day_no) { Date::DAYNAMES[day_no.to_i % 7] }
|
41
|
+
CASE WHEN date_part('dow', <%= plural_name %>.created_at) = 0 THEN 7 ELSE date_part('dow', <%= plural_name %>.created_at)::int END
|
42
|
+
SQL
|
43
|
+
dimension :hour_of_day, "date_part('hour', <%= plural_name %>.created_at)::int"
|
44
|
+
dimension :month, "date_part('month', <%= plural_name %>.created_at)::int",
|
35
45
|
label_method: ->(month_no) { Date::MONTHNAMES[month_no.to_i] }
|
36
|
-
dimension :week, "date_part('week', <%= plural_name %>.created_at)"
|
37
|
-
dimension :year, "date_part('year', <%= plural_name %>.created_at)"
|
46
|
+
dimension :week, "date_part('week', <%= plural_name %>.created_at)::int"
|
47
|
+
dimension :year, "date_part('year', <%= plural_name %>.created_at)::varchar"
|
38
48
|
|
39
49
|
# dimension :comments, 'SELECT count(*) FROM comments c WHERE c.<%= singular_name %>_id = <%= plural_name %>.id'
|
40
50
|
# dimension :user, 'users.name', includes: :user
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class <%= class_name %>DrilldownControllerTest < ActionDispatch::IntegrationTest
|
6
|
+
test 'should get index' do
|
7
|
+
get <%= singular_name %>_drilldown_url
|
8
|
+
assert_response :success
|
9
|
+
end
|
10
|
+
|
11
|
+
test 'should get index with list' do
|
12
|
+
get <%= singular_name %>_drilldown_url search: { list: 1 }
|
13
|
+
assert_response :success
|
14
|
+
end
|
15
|
+
end
|
@@ -4,51 +4,81 @@ require 'simple_drilldown/drilldown_helper'
|
|
4
4
|
require 'simple_drilldown/search'
|
5
5
|
|
6
6
|
module SimpleDrilldown
|
7
|
-
class
|
7
|
+
class Controller < ::ApplicationController
|
8
8
|
helper DrilldownHelper
|
9
9
|
|
10
10
|
LIST_LIMIT = 10_000
|
11
11
|
|
12
|
+
class_attribute :c_base_condition, default: '1=1'
|
13
|
+
class_attribute :c_base_group, default: []
|
14
|
+
class_attribute :c_base_includes, default: []
|
15
|
+
class_attribute :c_default_fields, default: []
|
16
|
+
class_attribute :c_default_select_value, default: SimpleDrilldown::Search::SelectValue::COUNT
|
17
|
+
class_attribute :c_dimension_defs
|
18
|
+
class_attribute :c_fields
|
19
|
+
class_attribute :c_list_includes, default: []
|
20
|
+
class_attribute :c_list_order
|
21
|
+
class_attribute :c_select, default: 'count(*) as count'
|
22
|
+
class_attribute :c_summary_fields, default: []
|
23
|
+
class_attribute :c_target_class
|
24
|
+
|
12
25
|
class << self
|
26
|
+
def inherited(base)
|
27
|
+
super
|
28
|
+
base.c_dimension_defs = Concurrent::Hash.new
|
29
|
+
base.c_fields = {}
|
30
|
+
begin
|
31
|
+
base.c_target_class = base.name.chomp('DrilldownController').constantize
|
32
|
+
rescue NameError
|
33
|
+
begin
|
34
|
+
base.c_target_class = base.name.chomp('Controller').constantize
|
35
|
+
rescue NameError
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
13
40
|
def base_condition(base_condition)
|
14
|
-
|
41
|
+
self.c_base_condition = base_condition
|
15
42
|
end
|
16
43
|
|
17
44
|
def base_includes(base_includes)
|
18
|
-
|
45
|
+
self.c_base_includes = base_includes
|
19
46
|
end
|
20
47
|
|
21
48
|
def base_group(base_group)
|
22
|
-
|
49
|
+
self.c_base_group = base_group
|
50
|
+
end
|
51
|
+
|
52
|
+
def default_fields(default_fields)
|
53
|
+
self.c_default_fields = default_fields.flatten
|
23
54
|
end
|
24
55
|
|
25
|
-
def
|
26
|
-
|
56
|
+
def default_select_value(default_select_value)
|
57
|
+
self.c_default_select_value = default_select_value
|
27
58
|
end
|
28
59
|
|
29
60
|
def target_class(target_class)
|
30
|
-
|
61
|
+
self.c_target_class = target_class
|
31
62
|
end
|
32
63
|
|
33
64
|
def select(select)
|
34
|
-
|
65
|
+
self.c_select = select
|
35
66
|
end
|
36
67
|
|
37
68
|
def list_includes(list_includes)
|
38
|
-
|
69
|
+
self.c_list_includes = list_includes.flatten
|
39
70
|
end
|
40
71
|
|
41
72
|
def list_order(list_order)
|
42
|
-
|
73
|
+
self.c_list_order = list_order
|
43
74
|
end
|
44
75
|
|
45
76
|
def field(name, **options)
|
46
|
-
|
47
|
-
@@fields[name] = options
|
77
|
+
c_fields[name] = options
|
48
78
|
end
|
49
79
|
|
50
80
|
def summary_fields(*summary_fields)
|
51
|
-
|
81
|
+
self.c_summary_fields = summary_fields.flatten
|
52
82
|
end
|
53
83
|
|
54
84
|
def dimension(name, select_expression = name, options = {})
|
@@ -74,15 +104,20 @@ module SimpleDrilldown
|
|
74
104
|
raise "Unknown options: #{query_opts.keys.inspect}" unless (query_opts.keys - %i[select includes where]).empty?
|
75
105
|
end
|
76
106
|
|
77
|
-
|
78
|
-
|
79
|
-
@@dimension_defs[name.to_s] = {
|
80
|
-
includes: queries.inject([]) do |a, e|
|
107
|
+
c_dimension_defs[name.to_s] = {
|
108
|
+
includes: queries.inject(nil) do |a, e|
|
81
109
|
i = e[:includes]
|
82
110
|
next a unless i
|
83
|
-
next a if a
|
111
|
+
next a if a&.include?(i)
|
84
112
|
|
85
|
-
a
|
113
|
+
case a
|
114
|
+
when nil
|
115
|
+
i
|
116
|
+
when Symbol
|
117
|
+
[a, *i]
|
118
|
+
else
|
119
|
+
a.concat(*i)
|
120
|
+
end
|
86
121
|
end,
|
87
122
|
interval: interval,
|
88
123
|
label_method: label_method,
|
@@ -101,7 +136,7 @@ module SimpleDrilldown
|
|
101
136
|
my_filter = search.filter.dup
|
102
137
|
my_filter.delete(field.to_s) unless preserve_filter
|
103
138
|
filter_conditions, _t, includes = make_conditions(my_filter)
|
104
|
-
dimension_def =
|
139
|
+
dimension_def = c_dimension_defs[field.to_s]
|
105
140
|
result_sets = dimension_def[:queries].map do |query|
|
106
141
|
if query[:includes]
|
107
142
|
if query[:includes].is_a?(Array)
|
@@ -111,11 +146,11 @@ module SimpleDrilldown
|
|
111
146
|
end
|
112
147
|
includes.uniq!
|
113
148
|
end
|
114
|
-
rows =
|
149
|
+
rows = c_target_class.unscoped.where(c_base_condition)
|
115
150
|
.select("#{query[:select]} AS value")
|
116
|
-
.where(filter_conditions)
|
117
|
-
.where(query[:where])
|
118
|
-
.joins(make_join([],
|
151
|
+
.where(filter_conditions || '1=1')
|
152
|
+
.where(query[:where] || '1=1')
|
153
|
+
.joins(make_join([], c_target_class.name.underscore.to_sym, includes))
|
119
154
|
.order('value')
|
120
155
|
.group(:value)
|
121
156
|
.to_a
|
@@ -137,14 +172,14 @@ module SimpleDrilldown
|
|
137
172
|
end
|
138
173
|
|
139
174
|
def make_conditions(search_filter)
|
140
|
-
includes =
|
175
|
+
includes = c_base_includes.dup
|
141
176
|
if search_filter
|
142
177
|
condition_strings = []
|
143
178
|
condition_values = []
|
144
179
|
|
145
180
|
filter_texts = []
|
146
181
|
search_filter.each do |field, values|
|
147
|
-
dimension_def =
|
182
|
+
dimension_def = c_dimension_defs[field]
|
148
183
|
raise "Unknown filter field: #{field.inspect}" if dimension_def.nil?
|
149
184
|
|
150
185
|
values = [*values]
|
@@ -202,9 +237,9 @@ module SimpleDrilldown
|
|
202
237
|
when Hash
|
203
238
|
sql = +''
|
204
239
|
include.each do |parent, child|
|
205
|
-
sql << make_join(joins, model, parent)
|
240
|
+
sql << ' ' + make_join(joins, model, parent)
|
206
241
|
ass = model.to_s.camelize.constantize.reflect_on_association parent
|
207
|
-
sql << make_join(joins, parent, child, ass.class_name.constantize)
|
242
|
+
sql << ' ' + make_join(joins, parent, child, ass.class_name.constantize)
|
208
243
|
end
|
209
244
|
sql
|
210
245
|
when Symbol
|
@@ -254,24 +289,7 @@ module SimpleDrilldown
|
|
254
289
|
|
255
290
|
def initialize
|
256
291
|
super()
|
257
|
-
@
|
258
|
-
@default_fields = @@default_fields
|
259
|
-
@default_select_value = SimpleDrilldown::Search::SelectValue::COUNT
|
260
|
-
@target_class = @@target_class
|
261
|
-
@select = @@select
|
262
|
-
@@base_condition = '1 = 1' unless defined?(@@base_condition)
|
263
|
-
@base_condition = @@base_condition
|
264
|
-
@@base_includes = [] unless defined?(@@base_includes)
|
265
|
-
@base_includes = @@base_includes
|
266
|
-
@base_group = defined?(@@base_group) ? @@base_group : []
|
267
|
-
@@list_includes = [] unless defined?(@@list_includes)
|
268
|
-
@list_includes = @@list_includes
|
269
|
-
@list_order = @@list_order
|
270
|
-
@dimension_defs = @@dimension_defs
|
271
|
-
@@summary_fields = [] unless defined?(@@summary_fields)
|
272
|
-
@summary_fields = @@summary_fields
|
273
|
-
|
274
|
-
@history_fields = @fields.select { |_k, v| v[:list_change_times] }.map { |k, _v| k.to_s }
|
292
|
+
@history_fields = c_fields.select { |_k, v| v[:list_change_times] }.map { |k, _v| k.to_s }
|
275
293
|
end
|
276
294
|
|
277
295
|
# ?dimension[0]=supplier&dimension[1]=transaction_type&
|
@@ -279,18 +297,17 @@ module SimpleDrilldown
|
|
279
297
|
def index(do_render = true)
|
280
298
|
@search = new_search_object
|
281
299
|
|
282
|
-
@transaction_fields = (@search.fields + (
|
283
|
-
@transaction_fields_map = @fields
|
300
|
+
@transaction_fields = (@search.fields + (c_fields.keys.map(&:to_s) - @search.fields))
|
284
301
|
|
285
|
-
select =
|
286
|
-
includes =
|
302
|
+
select = c_select.dup
|
303
|
+
includes = c_base_includes.dup
|
287
304
|
|
288
305
|
@dimensions = []
|
289
|
-
select << ", 'All'::text as value0"
|
306
|
+
select << ", 'All'#{'::text' if c_target_class.connection.adapter_name == 'PostgreSQL'} as value0"
|
290
307
|
@dimensions += @search.dimensions.map do |dn|
|
291
|
-
raise "Unknown distribution field: #{dn.inspect}" if
|
308
|
+
raise "Unknown distribution field: #{dn.inspect}" if c_dimension_defs[dn].nil?
|
292
309
|
|
293
|
-
|
310
|
+
c_dimension_defs[dn]
|
294
311
|
end
|
295
312
|
@dimensions.each_with_index do |d, i|
|
296
313
|
select << ", #{d[:select_expression]} as value#{i + 1}"
|
@@ -302,11 +319,11 @@ module SimpleDrilldown
|
|
302
319
|
includes.keep_if(&:present?).uniq!
|
303
320
|
if @search.order_by_value && @dimensions.size <= 1
|
304
321
|
order = case @search.select_value
|
305
|
-
when
|
322
|
+
when Search::SelectValue::VOLUME
|
306
323
|
'volume DESC'
|
307
|
-
when
|
324
|
+
when Search::SelectValue::VOLUME_COMPENSATED
|
308
325
|
'volume_compensated DESC'
|
309
|
-
when
|
326
|
+
when Search::SelectValue::COUNT
|
310
327
|
'count DESC'
|
311
328
|
else
|
312
329
|
'count DESC'
|
@@ -315,18 +332,18 @@ module SimpleDrilldown
|
|
315
332
|
order = (1..@dimensions.size).map { |i| "value#{i}" }.join(',')
|
316
333
|
order = nil if order.empty?
|
317
334
|
end
|
318
|
-
group = (
|
335
|
+
group = (c_base_group + (1..@dimensions.size).map { |i| "value#{i}" }).join(',')
|
319
336
|
group = nil if group.empty?
|
320
337
|
|
321
|
-
joins = self.class.make_join([],
|
322
|
-
rows =
|
323
|
-
|
324
|
-
|
325
|
-
|
338
|
+
joins = self.class.make_join([], c_target_class.name.underscore.to_sym, includes)
|
339
|
+
rows = c_target_class.unscoped.where(c_base_condition).select(select).where(conditions)
|
340
|
+
.joins(joins)
|
341
|
+
.group(group)
|
342
|
+
.order(order).to_a
|
326
343
|
|
327
344
|
if rows.empty?
|
328
345
|
@result = { value: 'All', count: 0, row_count: 0, nodes: 0, rows: [] }
|
329
|
-
|
346
|
+
c_summary_fields.each { |f| @result[f] = 0 }
|
330
347
|
else
|
331
348
|
if do_render && @search.list && rows.inject(0) { |sum, r| sum + r[:count].to_i } > LIST_LIMIT
|
332
349
|
@search.list = false
|
@@ -335,9 +352,9 @@ module SimpleDrilldown
|
|
335
352
|
@result = result_from_rows(rows, 0, 0, ['All'])
|
336
353
|
end
|
337
354
|
|
338
|
-
remove_duplicates(@result) unless
|
355
|
+
remove_duplicates(@result) unless c_base_group.empty?
|
339
356
|
|
340
|
-
@remaining_dimensions =
|
357
|
+
@remaining_dimensions = c_dimension_defs.dup
|
341
358
|
@remaining_dimensions.each_key do |dim_name|
|
342
359
|
if (@search.filter[dim_name] && @search.filter[dim_name].size == 1) ||
|
343
360
|
(@dimensions.any? { |d| d[:url_param_name] == dim_name })
|
@@ -352,9 +369,9 @@ module SimpleDrilldown
|
|
352
369
|
def choices
|
353
370
|
@search = new_search_object
|
354
371
|
dimension_name = params[:dimension_name]
|
355
|
-
dimension =
|
372
|
+
dimension = c_dimension_defs[dimension_name]
|
356
373
|
selected = @search.filter[dimension_name] || []
|
357
|
-
raise "Unknown dimension #{dimension_name.inspect}: #{
|
374
|
+
raise "Unknown dimension #{dimension_name.inspect}: #{c_dimension_defs.keys.inspect}" unless dimension
|
358
375
|
|
359
376
|
choices = [[t(:all), nil]] +
|
360
377
|
(dimension[:legal_values]&.call(@search)&.map { |o| o.is_a?(Array) ? o[0..1].map(&:to_s) : o.to_s } || [])
|
@@ -398,7 +415,7 @@ module SimpleDrilldown
|
|
398
415
|
private
|
399
416
|
|
400
417
|
def new_search_object
|
401
|
-
SimpleDrilldown::Search.new(params[:search]&.to_unsafe_h,
|
418
|
+
SimpleDrilldown::Search.new(params[:search]&.to_unsafe_h, c_default_fields, c_default_select_value)
|
402
419
|
end
|
403
420
|
|
404
421
|
def remove_duplicates(result)
|
@@ -411,7 +428,7 @@ module SimpleDrilldown
|
|
411
428
|
if prev_row
|
412
429
|
if prev_row[:value] == r[:value]
|
413
430
|
prev_row[:count] += r[:count]
|
414
|
-
|
431
|
+
c_summary_fields.each do |f|
|
415
432
|
prev_row[f] += r[f]
|
416
433
|
end
|
417
434
|
prev_row[:row_count] = [prev_row[:row_count], r[:row_count]].max
|
@@ -449,7 +466,7 @@ module SimpleDrilldown
|
|
449
466
|
row_count: 0,
|
450
467
|
nodes: 0
|
451
468
|
}
|
452
|
-
|
469
|
+
c_summary_fields.each { |f| sub_result[f] = 0 }
|
453
470
|
sub_result[:rows] = add_zero_results([], dimension + 1) if dimension < @dimensions.size - 1
|
454
471
|
result_rows << sub_result
|
455
472
|
end
|
@@ -472,7 +489,7 @@ module SimpleDrilldown
|
|
472
489
|
row_count: 1,
|
473
490
|
nodes: @search.list ? 2 : 1
|
474
491
|
}
|
475
|
-
|
492
|
+
c_summary_fields.each { |f| result[f] = row[f].to_i }
|
476
493
|
return result
|
477
494
|
end
|
478
495
|
|
@@ -495,37 +512,75 @@ module SimpleDrilldown
|
|
495
512
|
nodes: result_rows.inject(0) { |t, r| t + r[:nodes] } + 1,
|
496
513
|
rows: result_rows
|
497
514
|
}
|
498
|
-
|
515
|
+
c_summary_fields.each { |f| result[f] = result_rows.inject(0) { |t, r| t + r[f] } }
|
499
516
|
result
|
500
517
|
end
|
501
518
|
|
502
519
|
def populate_list(conditions, includes, result, values)
|
503
520
|
if result[:rows]
|
504
|
-
result[:rows].each
|
505
|
-
|
521
|
+
return result[:rows].each { |r| populate_list(conditions, includes, r, values + [r[:value]]) }
|
522
|
+
end
|
523
|
+
list_includes = merge_includes(includes, c_list_includes)
|
524
|
+
@search.fields.each do |field|
|
525
|
+
field_def = c_fields[field.to_sym]
|
526
|
+
raise "Field definition missing for: #{field.inspect}" unless field_def
|
527
|
+
|
528
|
+
field_includes = field_def[:include]
|
529
|
+
if field_includes
|
530
|
+
list_includes = merge_includes(list_includes , field_includes)
|
506
531
|
end
|
507
|
-
|
508
|
-
|
509
|
-
@
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
field_includes = field_def[:include]
|
514
|
-
if field_includes
|
515
|
-
list_includes += field_includes.is_a?(Array) ? field_includes : [field_includes]
|
532
|
+
end
|
533
|
+
if @search.list_change_times
|
534
|
+
@history_fields.each do |f|
|
535
|
+
if @search.fields.include? f
|
536
|
+
list_includes = merge_includes(list_includes, assignment: { order: :"#{f}_changes" } )
|
516
537
|
end
|
517
538
|
end
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
539
|
+
end
|
540
|
+
joins = self.class.make_join([], c_target_class.name.underscore.to_sym, list_includes)
|
541
|
+
list_conditions = list_conditions(conditions, values)
|
542
|
+
base_query = c_target_class.unscoped.where(c_base_condition).joins(joins).order(@list_order)
|
543
|
+
base_query = base_query.where(list_conditions) if list_conditions
|
544
|
+
result[:transactions] = base_query.to_a
|
545
|
+
end
|
546
|
+
|
547
|
+
def merge_includes(*args)
|
548
|
+
hash = hash_includes(*args)
|
549
|
+
result = hash.dup.map { |k, v|
|
550
|
+
if v.blank?
|
551
|
+
hash.delete(k)
|
552
|
+
k
|
553
|
+
end
|
554
|
+
}.compact
|
555
|
+
result << hash unless hash.blank?
|
556
|
+
case result.size
|
557
|
+
when 0
|
558
|
+
nil
|
559
|
+
when 1
|
560
|
+
result[0]
|
561
|
+
else
|
562
|
+
result
|
563
|
+
end
|
564
|
+
end
|
565
|
+
|
566
|
+
def hash_includes(*args)
|
567
|
+
args.inject({}) do |h, inc|
|
568
|
+
case inc
|
569
|
+
when Array
|
570
|
+
inc.each { |v|
|
571
|
+
h = hash_includes(h, v)
|
572
|
+
}
|
573
|
+
when Hash
|
574
|
+
inc.each { |k, v|
|
575
|
+
h[k] = merge_includes(h[k], v)
|
576
|
+
}
|
577
|
+
when NilClass, FalseClass
|
578
|
+
when String, Symbol
|
579
|
+
h[inc] ||= []
|
580
|
+
else
|
581
|
+
raise "Unknown include type: #{inc.inspect}"
|
523
582
|
end
|
524
|
-
|
525
|
-
list_conditions = list_conditions(conditions, values)
|
526
|
-
base_query = @target_class.unscoped.where(@base_condition).joins(joins).order(@list_order)
|
527
|
-
base_query = base_query.where(list_conditions) if list_conditions
|
528
|
-
result[:transactions] = base_query.to_a
|
583
|
+
h
|
529
584
|
end
|
530
585
|
end
|
531
586
|
|
@@ -1,67 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module SimpleDrilldown
|
4
|
+
# View helper for SimpleDrilldown
|
5
|
+
# FIXME(uwe): Rename to Helper
|
2
6
|
module DrilldownHelper
|
3
7
|
def value_label(dimension_index, value)
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
+
dimension = @dimensions[dimension_index]
|
9
|
+
return nil if dimension.nil?
|
10
|
+
|
11
|
+
h(dimension[:label_method] ? dimension[:label_method].call(value) : value)
|
8
12
|
end
|
9
13
|
|
10
14
|
def caption
|
11
|
-
result = @search.title
|
12
|
-
|
15
|
+
result = @search.title || "#{controller.c_target_class} #{t(@search.select_value.downcase)}" +
|
16
|
+
(@dimensions && @dimensions.any? ? ' by ' + @dimensions.map { |d| d[:pretty_name] }.join(' and ') : '')
|
13
17
|
result.gsub('$date', [*@search.filter[:calendar_date]].uniq.join(' - '))
|
14
18
|
end
|
15
19
|
|
16
20
|
def subcaption
|
17
|
-
@search.title
|
21
|
+
@search.title || @filter_text.blank? ? '' : "for #{@filter_text}"
|
18
22
|
end
|
19
23
|
|
20
24
|
def summary_row(result, parent_result = nil, dimension = 0, headers = [], new_row = true)
|
21
|
-
html = render(:
|
25
|
+
html = render(partial: '/drilldown/summary_row', locals: { result: result, parent_result: parent_result, new_row: new_row, dimension: dimension, headers: headers, with_results: !result[:rows] })
|
22
26
|
if result[:rows]
|
23
|
-
sub_headers = headers + [{ :
|
24
|
-
significant_rows = result[:rows].
|
27
|
+
sub_headers = headers + [{ value: result[:value], display_row_count: result[:nodes] + result[:row_count] * (@search.list ? 1 : 0) }]
|
28
|
+
significant_rows = result[:rows].reject { |r| r[:row_count].zero? }
|
25
29
|
significant_rows.each_with_index do |r, i|
|
26
|
-
html << summary_row(r, result, dimension + 1, sub_headers, i
|
30
|
+
html << summary_row(r, result, dimension + 1, sub_headers, i.positive?)
|
27
31
|
end
|
28
32
|
elsif @search.list
|
29
|
-
html << render(:
|
30
|
-
end
|
31
|
-
if dimension < @dimensions.size
|
32
|
-
html << render(:partial => '/drilldown/summary_total_row', :locals => { :result => result, :parent_result => parent_result, :headers => headers.dup, :dimension => dimension })
|
33
|
+
html << render(partial: '/drilldown/record_list', locals: { result: result })
|
33
34
|
end
|
35
|
+
html << render(partial: '/drilldown/summary_total_row', locals: { result: result, parent_result: parent_result, headers: headers.dup, dimension: dimension }) if dimension < @dimensions.size
|
34
36
|
|
35
37
|
html
|
36
38
|
end
|
37
39
|
|
38
40
|
def excel_summary_row(result, parent_result = nil, dimension = 0, headers = [])
|
39
|
-
xml = ''
|
41
|
+
xml = +''
|
40
42
|
if result[:rows]
|
41
|
-
significant_rows = result[:rows].
|
43
|
+
significant_rows = result[:rows].reject { |r| r[:row_count].zero? }
|
42
44
|
significant_rows.each_with_index do |r, i|
|
43
|
-
if i
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
45
|
+
sub_headers = if i.zero?
|
46
|
+
if dimension.zero?
|
47
|
+
headers
|
48
|
+
else
|
49
|
+
headers + [{ value: result[:value], display_row_count: result[:nodes] + result[:row_count] * (@search.list ? 1 : 0) }]
|
50
|
+
end
|
51
|
+
else
|
52
|
+
[] # [{:value => result[:value], :row_count => result[:row_count]}]
|
53
|
+
end
|
52
54
|
xml << excel_summary_row(r, result, dimension + 1, sub_headers)
|
53
55
|
end
|
54
56
|
else
|
55
|
-
xml << render(:
|
57
|
+
xml << render(partial: '/drilldown/excel_summary_row', locals: { result: result, parent_result: parent_result, headers: headers.dup, dimension: dimension })
|
56
58
|
|
57
|
-
if @search.list
|
58
|
-
xml << render(:partial => '/drilldown/excel_record_list', :locals => { :result => result })
|
59
|
-
end
|
59
|
+
xml << render(partial: '/drilldown/excel_record_list', locals: { result: result }) if @search.list
|
60
60
|
end
|
61
61
|
|
62
|
-
if dimension < @dimensions.size
|
63
|
-
xml << render(:partial => '/drilldown/excel_summary_total_row', :locals => { :result => result, :headers => headers.dup, :dimension => dimension })
|
64
|
-
end
|
62
|
+
xml << render(partial: '/drilldown/excel_summary_total_row', locals: { result: result, headers: headers.dup, dimension: dimension }) if dimension < @dimensions.size
|
65
63
|
xml
|
66
64
|
end
|
67
65
|
end
|
@@ -1,11 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'chartkick'
|
4
|
+
require 'simple_drilldown/routing'
|
5
|
+
|
3
6
|
module SimpleDrilldown
|
4
7
|
class Engine < ::Rails::Engine
|
5
8
|
isolate_namespace SimpleDrilldown
|
9
|
+
config.autoload_paths << File.dirname(__dir__)
|
6
10
|
|
7
11
|
initializer 'simple_drilldown.assets.precompile' do |app|
|
8
12
|
app.config.assets.precompile += %w[chartkick.js]
|
9
13
|
end
|
14
|
+
|
15
|
+
ActionDispatch::Routing::Mapper.include SimpleDrilldown::Routing
|
10
16
|
end
|
11
17
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SimpleDrilldown
|
4
|
+
# Routing helper methods
|
5
|
+
module Routing
|
6
|
+
def draw_drilldown(path, controller = path)
|
7
|
+
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
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
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.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Uwe Kubosch
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-09-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chartkick
|
@@ -90,7 +90,7 @@ files:
|
|
90
90
|
- app/jobs/simple_drilldown/application_job.rb
|
91
91
|
- app/mailers/simple_drilldown/application_mailer.rb
|
92
92
|
- app/models/simple_drilldown/application_record.rb
|
93
|
-
- app/views/drilldown/_chart.html.
|
93
|
+
- app/views/drilldown/_chart.html.erb
|
94
94
|
- app/views/drilldown/_excel_record_list.builder
|
95
95
|
- app/views/drilldown/_excel_row.builder
|
96
96
|
- app/views/drilldown/_excel_row_header.builder
|
@@ -123,10 +123,12 @@ files:
|
|
123
123
|
- lib/generators/drilldown_controller/USAGE
|
124
124
|
- lib/generators/drilldown_controller/drilldown_controller_generator.rb
|
125
125
|
- lib/generators/drilldown_controller/templates/drilldown_controller.rb.erb
|
126
|
+
- lib/generators/drilldown_controller/templates/drilldown_controller_test.rb.erb
|
126
127
|
- lib/simple_drilldown.rb
|
127
|
-
- lib/simple_drilldown/
|
128
|
+
- lib/simple_drilldown/controller.rb
|
128
129
|
- lib/simple_drilldown/drilldown_helper.rb
|
129
130
|
- lib/simple_drilldown/engine.rb
|
131
|
+
- lib/simple_drilldown/routing.rb
|
130
132
|
- lib/simple_drilldown/search.rb
|
131
133
|
- lib/simple_drilldown/version.rb
|
132
134
|
- lib/tasks/simple_drilldown_tasks.rake
|
@@ -135,7 +137,7 @@ licenses:
|
|
135
137
|
- MIT
|
136
138
|
metadata:
|
137
139
|
allowed_push_host: https://rubygems.org/
|
138
|
-
post_install_message:
|
140
|
+
post_install_message:
|
139
141
|
rdoc_options: []
|
140
142
|
require_paths:
|
141
143
|
- lib
|
@@ -151,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
151
153
|
version: '0'
|
152
154
|
requirements: []
|
153
155
|
rubygems_version: 3.1.2
|
154
|
-
signing_key:
|
156
|
+
signing_key:
|
155
157
|
specification_version: 4
|
156
158
|
summary: Simple data warehouse and drilldown.
|
157
159
|
test_files: []
|
@@ -1,52 +0,0 @@
|
|
1
|
-
ruby:
|
2
|
-
data =
|
3
|
-
case @dimensions.size
|
4
|
-
when 0
|
5
|
-
{ @result[:value] => @result[:count] }
|
6
|
-
when 1
|
7
|
-
@result[:rows].map { |r| [ @dimensions[0][:label_method] ? @dimensions[0][:label_method].call(r[:value]) : r[:value], r[:count] ] }
|
8
|
-
when 2
|
9
|
-
@result[:rows].map do |r|
|
10
|
-
{
|
11
|
-
name: r[:value],
|
12
|
-
data: r[:rows].map { |r2| [r2[:value], r2[:count]] }
|
13
|
-
}
|
14
|
-
end
|
15
|
-
when 3
|
16
|
-
end
|
17
|
-
- case @search.display_type
|
18
|
-
- when SimpleDrilldown::Search::DisplayType::PIE
|
19
|
-
= pie_chart data, height: '24rem'
|
20
|
-
- when SimpleDrilldown::Search::DisplayType::BAR
|
21
|
-
= column_chart data, height: '24rem'
|
22
|
-
- when SimpleDrilldown::Search::DisplayType::LINE
|
23
|
-
= line_chart data, height: '24rem'
|
24
|
-
- else
|
25
|
-
#drilldown_area
|
26
|
-
h2 = caption
|
27
|
-
h3 = subcaption
|
28
|
-
br
|
29
|
-
#drilldown_search_area style="margin-left: auto; margin-right: auto; text-align: center"
|
30
|
-
- (0..2).each do |i|
|
31
|
-
- options = [['', '']]
|
32
|
-
- options << [@dimensions[i][:pretty_name], @dimensions[i][:url_param_name]] if @dimensions[i]
|
33
|
-
- options += @remaining_dimensions.keys.map { |name| [@dimension_defs[name][:pretty_name], name] }
|
34
|
-
| #{t(i == 0 ? :group_by : :then_by)}:
|
35
|
-
= form.select 'dimensions', options, { :selected => @search.dimensions && @search.dimensions[i] }, \
|
36
|
-
{ :onChange => 'form.submit()', :name => 'search[dimensions][]', :id => "search_dimensions_#{i}" }
|
37
|
-
br
|
38
|
-
= t :chart_type
|
39
|
-
= form.radio_button 'display_type', SimpleDrilldown::Search::DisplayType::BAR, { :onChange => 'form.submit()' }
|
40
|
-
= form.label :display_type_bar, t(:bar)
|
41
|
-
= form.radio_button 'display_type', SimpleDrilldown::Search::DisplayType::PIE, { :disabled => @search.dimensions.size >= 2, :onChange => 'form.submit()' }
|
42
|
-
= form.label :display_type_pie, t(:pie)
|
43
|
-
= form.radio_button 'display_type', SimpleDrilldown::Search::DisplayType::LINE, { :onChange => 'form.submit()' }
|
44
|
-
= form.label :display_type_line, t(:line)
|
45
|
-
= form.radio_button 'display_type', SimpleDrilldown::Search::DisplayType::NONE, { :onChange => 'form.submit()' }
|
46
|
-
= form.label :display_type_none, t(:none)
|
47
|
-
|
48
|
-
= form.check_box :order_by_value, { :onChange => 'form.submit()' }
|
49
|
-
= form.label :order_by_value, t(:order_by_value)
|
50
|
-
|
51
|
-
= form.check_box :list, { :onChange => 'form.submit()' }
|
52
|
-
= form.label :list, t(:list)
|