simple_drilldown 0.9.11 → 0.11.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4bf78b23713b09e5007b4b8ab3c084e511bdb2cd620f45b9e8d8f4b8d181729c
4
- data.tar.gz: 37110d16927f895350153faaec36bead96f2bf9f6b4263e014eaffe46eb52ecc
3
+ metadata.gz: 1e99331c0a6ab073aece756d21fc1e639e426321975ffd23f64c1becddc375d8
4
+ data.tar.gz: 6db7888ff16123847f4df9f3b780fa9232af484c26abcacd38f45a56a25cccca
5
5
  SHA512:
6
- metadata.gz: d9a1f536867c67dd52cebfc34ed71e0c67e121f181afc0b169e00640176776fb9909ac049214eaadc06e886744cde84efc35d70a1009a6977478c90141254bc2
7
- data.tar.gz: 4ac0a883010bdddfe9e5eaa81d87e41f8f5e2ea018d33297c80395154c9b2c45ca8efd024edb465cda8c779f24a0ca00d5a15b8cb6ac4ebe0d0d72647c6e5747
6
+ metadata.gz: 0002a2f6172dcd658e8bc329ed3985b3829690844c93b01d6a597083a0e59123b9c3fe5ad78f189a6041b8ad2ec82da0ff6e62a55dfe6e4118d2611aa9bde0c9
7
+ data.tar.gz: b877aab5468b90bccf608b854b3f362db63d36c4edd6806be9daed15136d54000f435a9047acd308b9016c5a194a4eed8fa86c58a1d73cc21bcbcc12d442b8b9
data/README.md CHANGED
@@ -66,7 +66,7 @@ end
66
66
  Create a new controller to focus on posts. Each drilldown controller focuses on
67
67
  one main entity.
68
68
 
69
- bin/rails g drilldown_controller User
69
+ bin/rails g simple_drilldown:controller User
70
70
 
71
71
  ```ruby
72
72
  class PostsDrilldownController < DrilldownController
@@ -115,8 +115,12 @@ results.
115
115
 
116
116
  ### Views
117
117
 
118
- You need the following views:
118
+ This gem includes views for the drilldown visualization using Bootstrap.
119
119
 
120
+ You can override any views by creating them in your `app/views/drilldown` directory.
121
+ If you would like a local copy of the views for overriding you can use the generator.
122
+
123
+ bin/rails g simple_drilldown:views
120
124
 
121
125
 
122
126
  ## Excel export
@@ -41,12 +41,12 @@
41
41
  options << [@dimensions[i][:pretty_name], @dimensions[i][:url_param_name]] if @dimensions[i]
42
42
  options += @remaining_dimensions.keys.map { |name| [controller.c_dimension_defs[name][:pretty_name], name] } %>
43
43
  <%= t(i == 0 ? :group_by : :then_by) %>:
44
- <%= form.select 'dimensions', options, { :selected => @search.dimensions && @search.dimensions[i] },
44
+ <%= form.select 'dimensions', options.sort, { :selected => @search.dimensions && @search.dimensions[i] },
45
45
  { onChange: 'form.submit()', name: 'search[dimensions][]', id: "search_dimensions_#{i}" } %>
46
46
  <% end %>
47
47
 
48
48
  <br/>
49
- <%= t :chart_type %>
49
+ <%= t :chart_type %>:
50
50
  <%= form.radio_button 'display_type', SimpleDrilldown::Search::DisplayType::BAR, { :onChange => 'form.submit()' } %>
51
51
  <%= form.label :display_type_bar, t(:bar) %>
52
52
  <%= form.radio_button 'display_type', SimpleDrilldown::Search::DisplayType::PIE, { :disabled => @search.dimensions.size >= 2, :onChange => 'form.submit()' } %>
@@ -4,7 +4,7 @@ xml.chart(
4
4
  xAxisName: (@dimensions[0][:pretty_name] || 'Elections').gsub("'", ''), palette: '2',
5
5
  caption: caption, subcaption: subcaption,
6
6
  showNames: '1',
7
- showValues: @result[:rows].size > 15 || @result[:rows][0] && @result[:rows][0][:rows].size > 4 ? 0 : 1,
7
+ showValues: @result[:rows].size > 15 || (@result[:rows][0] && @result[:rows][0][:rows].size > 4) ? 0 : 1,
8
8
  decimals: '0',
9
9
  numberPrefix: '', clustered: '0', exeTime: '1.5', showPlotBorder: '0', zGapPlot: '30',
10
10
  zDepth: '90', divLineEffect: 'emboss', startAngX: '10', endAngX: '18', startAngY: '-10',
@@ -5,7 +5,7 @@ xml.chart(
5
5
  caption: caption, subcaption: subcaption,
6
6
  showNames: '1',
7
7
  showValues:
8
- @result[:rows].size > 15 || @result[:rows][0] && @result[:rows][0][:rows].size > 4 ? 0 : 1,
8
+ @result[:rows].size > 15 || (@result[:rows][0] && @result[:rows][0][:rows].size > 4) ? 0 : 1,
9
9
  decimals: '0',
10
10
  numberPrefix: '', clustered: '0', exeTime: '1.5', showPlotBorder: '0', zGapPlot: '30',
11
11
  zDepth: '90', divLineEffect: 'emboss', startAngX: '10', endAngX: '18', startAngY: '-10',
@@ -11,7 +11,7 @@ def excel_summary_row_xlsx(sheet, result, parent_result = nil, dimension = 0, he
11
11
  else
12
12
  headers + [{
13
13
  value: result[:value],
14
- display_row_count: result[:nodes] + result[:row_count] * (@search.list ? 1 : 0)
14
+ display_row_count: result[:nodes] + (result[:row_count] * (@search.list ? 1 : 0))
15
15
  }]
16
16
  end
17
17
  else
@@ -17,8 +17,9 @@
17
17
  <div class="col-md-3" valign="top">
18
18
  <ul class="nav nav-tabs">
19
19
  <li class="nav-item">
20
- <a id="filter-tab" class="nav-link active" data-target="#filter" data-toggle="tab"><%= t :filter %></a></li>
21
- <li><a id="fields-tab" class="nav-link" data-target="#fields" data-toggle="tab"><%= t :fields %></a>
20
+ <a id="filter-tab" class="nav-link active" data-target="#filter" data-toggle="tab" data-bs-toggle="tab" data-bs-target="#filter"><%= t :filter %></a></li>
21
+ <li class="nav-item">
22
+ <a id="fields-tab" class="nav-link" data-target="#fields" data-toggle="tab" data-bs-toggle="tab" data-bs-target="#fields"><%= t :fields %></a>
22
23
  </li>
23
24
  </ul>
24
25
 
@@ -2,7 +2,7 @@ Description:
2
2
  Create a DrilldownController.
3
3
 
4
4
  Example:
5
- rails generate drilldown_controller Thing
5
+ rails generate simple_drilldown:controller Thing
6
6
 
7
7
  This will create:
8
8
  app/controllers/thing_drilldown_controller.rb
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SimpleDrilldown
4
+ class ControllerGenerator < Rails::Generators::NamedBase
5
+ source_root File.expand_path('templates', __dir__)
6
+
7
+ def copy_drilldown_controller_file
8
+ template 'drilldown_controller.rb.erb', "app/controllers/#{file_name}_drilldown_controller.rb"
9
+ template 'drilldown_controller_test.rb.erb', "test/controllers/#{file_name}_drilldown_controller_test.rb"
10
+ route "draw_drilldown :#{singular_name}"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ Description:
2
+ Generate drilldown views.
3
+
4
+ Example:
5
+ bin/rails generate simple_drilldown:views
6
+
7
+ This will create:
8
+ app/views/drilldown
9
+ app/views/layouts/drilldown
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SimpleDrilldown
4
+ class ViewsGenerator < Rails::Generators::Base
5
+ source_root File.expand_path('../../../../', __dir__)
6
+
7
+ def copy_drilldown_views_file
8
+ directory 'app/views'
9
+ end
10
+ end
11
+ end
@@ -36,9 +36,7 @@ module SimpleDrilldown
36
36
  # No default target class found
37
37
  end
38
38
  end
39
- return unless base.c_target_class.try :paranoid?
40
-
41
- base.c_base_condition = "#{base.c_target_class.table_name}.deleted_at IS NULL"
39
+ base.update_base_condition
42
40
  end
43
41
 
44
42
  def base_condition(base_condition)
@@ -63,6 +61,7 @@ module SimpleDrilldown
63
61
 
64
62
  def target_class(target_class)
65
63
  self.c_target_class = target_class
64
+ update_base_condition
66
65
  end
67
66
 
68
67
  def select(select)
@@ -136,7 +135,9 @@ module SimpleDrilldown
136
135
  interval: interval,
137
136
  label_method: label_method,
138
137
  legal_values: legal_values,
139
- pretty_name: I18n.t(name, default: [:"activerecord.models.#{name}", name.to_s.titleize]),
138
+ pretty_name: I18n.t(:"drilldown.dimension.#{name}",
139
+ default: [:"drilldown.#{name}", :"activerecord.models.#{name}", name.to_sym,
140
+ name.to_s.titleize]),
140
141
  queries: queries,
141
142
  reverse: reverse,
142
143
  select_expression:
@@ -148,25 +149,18 @@ module SimpleDrilldown
148
149
 
149
150
  def legal_values_for(field, preserve_filter = false)
150
151
  lambda do |search|
151
- my_filter = search.filter.dup
152
- my_filter.delete(field.to_s) unless preserve_filter
153
- filter_conditions, _t, includes = make_conditions(my_filter)
152
+ filter = search.filter.dup
153
+ filter.delete(field.to_s) unless preserve_filter
154
+ filter_conditions, _t, includes = make_conditions(filter)
154
155
  dimension_def = c_dimension_defs[field.to_s]
155
156
  result_sets = dimension_def[:queries].map do |query|
156
- if query[:includes]
157
- if query[:includes].is_a?(Array)
158
- includes += query[:includes]
159
- else
160
- includes << query[:includes]
161
- end
162
- includes.uniq!
163
- end
157
+ includes = merge_includes(includes, query[:includes]) if query[:includes]
164
158
  rows_query = c_target_class.unscoped.where(c_base_condition)
165
159
  .select("#{query[:select]} AS value")
166
160
  .joins(make_join([], c_target_class.name.underscore.to_sym, includes))
167
161
  .order('value')
168
162
  .group(:value)
169
- # rows_query = rows_query.without_deleted if c_target_class.try :paranoid?
163
+ rows_query = rows_query.without_deleted if c_target_class.try :paranoid?
170
164
  rows_query = rows_query.where(filter_conditions) if filter_conditions
171
165
  rows_query = rows_query.where(query[:where]) if query[:where]
172
166
  rows = rows_query.to_a
@@ -275,8 +269,8 @@ module SimpleDrilldown
275
269
  fk_col = ass.options[:foreign_key] || "#{model}_id"
276
270
  sql = +"LEFT JOIN #{include_table} #{include_alias} ON #{include_alias}.#{fk_col} = #{model_table}.id"
277
271
  sql << " AND #{include_alias}.deleted_at IS NULL" if ass.klass.paranoid?
278
- if ass.scope && (ass_order = ScopeHolder.new(ass.scope).to_s)
279
- ass_order = ass_order.sub(/ DESC\s*$/i, '')
272
+ if ass.scope && (base_ass_order = ScopeHolder.new(ass.scope).to_s)
273
+ /^(?<ass_order>\S*)(?<ass_order_desc>\s+DESC)?/i =~ base_ass_order
280
274
  ass_order_prefixed = ass_order.dup
281
275
  ActiveRecord::Base.connection.columns(include_table).map(&:name).each do |cname|
282
276
  ass_order_prefixed.gsub!(/\b#{cname}\b/, "#{include_alias}.#{cname}")
@@ -284,10 +278,10 @@ module SimpleDrilldown
284
278
  paranoid_clause = 'AND t2.deleted_at IS NULL' if ass.klass.paranoid?
285
279
  # FIXME(uwe): Should we add "where" from the ScopeHolder here as well?
286
280
  # Ref: SimpleDrilldown::Changes#changes_for
287
- min_query = <<~SQL
288
- SELECT MIN(#{ass_order}) FROM #{include_table} t2 WHERE t2.#{fk_col} = #{model_table}.id #{paranoid_clause}
281
+ aggregate_query = <<~SQL
282
+ SELECT #{ass_order_desc ? :MAX : :MIN}(#{ass_order}) FROM #{include_table} t2 WHERE t2.#{fk_col} = #{model_table}.id #{paranoid_clause}
289
283
  SQL
290
- sql << " AND #{ass_order_prefixed} = (#{min_query})"
284
+ sql << " AND #{ass_order_prefixed} = (#{aggregate_query})"
291
285
  end
292
286
  sql
293
287
  else
@@ -301,6 +295,51 @@ module SimpleDrilldown
301
295
  raise "Unknown join class: #{include.inspect}"
302
296
  end
303
297
  end
298
+
299
+ def merge_includes(*args)
300
+ hash = hash_includes(*args)
301
+ result = hash.dup.map do |k, v|
302
+ if v.blank?
303
+ hash.delete(k)
304
+ k
305
+ end
306
+ end.compact
307
+ result << hash unless hash.blank?
308
+ case result.size
309
+ when 0
310
+ nil
311
+ when 1
312
+ result[0]
313
+ else
314
+ result
315
+ end
316
+ end
317
+
318
+ def hash_includes(*args)
319
+ args.inject({}) do |h, inc|
320
+ case inc
321
+ when Array
322
+ inc.each do |v|
323
+ h = hash_includes(h, v)
324
+ end
325
+ when Hash
326
+ inc.each do |k, v|
327
+ h[k] = merge_includes(h[k], v)
328
+ end
329
+ when NilClass, FalseClass
330
+ # Leave as it is
331
+ when String, Symbol
332
+ h[inc] ||= []
333
+ else
334
+ raise "Unknown include type: #{inc.inspect}"
335
+ end
336
+ h
337
+ end
338
+ end
339
+
340
+ def update_base_condition
341
+ self.c_base_condition = "#{c_target_class.table_name}.deleted_at IS NULL" if c_target_class.try :paranoid?
342
+ end
304
343
  end
305
344
 
306
345
  def initialize
@@ -535,18 +574,18 @@ module SimpleDrilldown
535
574
  def populate_list(conditions, includes, result, values)
536
575
  return result[:rows].each { |r| populate_list(conditions, includes, r, values + [r[:value]]) } if result[:rows]
537
576
 
538
- list_includes = merge_includes(includes, c_list_includes)
577
+ list_includes = self.class.merge_includes(includes, c_list_includes)
539
578
  @search.fields.each do |field|
540
579
  field_def = c_fields[field.to_sym]
541
580
  raise "Field definition missing for: #{field.inspect}" unless field_def
542
581
 
543
582
  field_includes = field_def[:include]
544
- list_includes = merge_includes(list_includes, field_includes) if field_includes
583
+ list_includes = self.class.merge_includes(list_includes, field_includes) if field_includes
545
584
  end
546
585
  if @search.list_change_times
547
586
  @history_fields.each do |f|
548
587
  if @search.fields.include? f
549
- list_includes = merge_includes(list_includes, assignment: { order: :"#{f}_changes" })
588
+ list_includes = self.class.merge_includes(list_includes, assignment: { order: :"#{f}_changes" })
550
589
  end
551
590
  end
552
591
  end
@@ -557,47 +596,6 @@ module SimpleDrilldown
557
596
  result[:records] = base_query.to_a
558
597
  end
559
598
 
560
- def merge_includes(*args)
561
- hash = hash_includes(*args)
562
- result = hash.dup.map do |k, v|
563
- if v.blank?
564
- hash.delete(k)
565
- k
566
- end
567
- end.compact
568
- result << hash unless hash.blank?
569
- case result.size
570
- when 0
571
- nil
572
- when 1
573
- result[0]
574
- else
575
- result
576
- end
577
- end
578
-
579
- def hash_includes(*args)
580
- args.inject({}) do |h, inc|
581
- case inc
582
- when Array
583
- inc.each do |v|
584
- h = hash_includes(h, v)
585
- end
586
- when Hash
587
- inc.each do |k, v|
588
- h[k] = merge_includes(h[k], v)
589
- end
590
- when NilClass, FalseClass
591
- # Leave as it is
592
- when String, Symbol
593
- h[inc] ||= []
594
- else
595
- raise "Unknown include type: #{inc.inspect}"
596
- end
597
- h
598
- end
599
- end
600
-
601
599
  def list_conditions(conditions, values)
602
600
  conditions ||= ['']
603
601
 
@@ -31,7 +31,7 @@ module SimpleDrilldown
31
31
  if result[:rows]
32
32
  sub_headers = headers + [{
33
33
  value: result[:value],
34
- display_row_count: result[:nodes] + result[:row_count] * (@search.list ? 1 : 0)
34
+ display_row_count: result[:nodes] + (result[:row_count] * (@search.list ? 1 : 0))
35
35
  }]
36
36
  significant_rows = result[:rows].reject { |r| r[:row_count].zero? }
37
37
  significant_rows.each_with_index do |r, i|
@@ -62,7 +62,7 @@ module SimpleDrilldown
62
62
  else
63
63
  headers + [{
64
64
  value: result[:value],
65
- display_row_count: result[:nodes] + result[:row_count] * (@search.list ? 1 : 0)
65
+ display_row_count: result[:nodes] + (result[:row_count] * (@search.list ? 1 : 0))
66
66
  }]
67
67
  end
68
68
  else
@@ -89,9 +89,13 @@ module SimpleDrilldown
89
89
  private
90
90
 
91
91
  def caption_txt
92
- "#{controller.c_target_class} #{I18n.t(@search.select_value.downcase,
93
- default: @search.select_value.to_s.titleize)}" +
94
- (@dimensions && @dimensions.any? ? " by #{@dimensions.map { |d| d[:pretty_name] }.join(' and ')}" : '')
92
+ class_txt = controller.c_target_class &&
93
+ I18n.t(controller.c_target_class.name.pluralize.to_sym,
94
+ default: [controller.c_target_class.name.downcase.pluralize.to_sym,
95
+ controller.c_target_class.name.pluralize])
96
+ value_txt = I18n.t(@search.select_value.downcase, default: @search.select_value.to_s.titleize)
97
+ dimensions_txt = " by #{@dimensions.map { |d| d[:pretty_name] }.join(' and ')}" if @dimensions&.any?
98
+ "#{class_txt} #{value_txt}#{dimensions_txt}"
95
99
  end
96
100
  end
97
101
  end
@@ -47,7 +47,7 @@ module SimpleDrilldown
47
47
  attributes = attributes_or_search
48
48
  @default_fields = default_fields
49
49
  @default_select_value = default_select_value
50
- @dimensions = attributes && attributes[:dimensions] || []
50
+ @dimensions = (attributes && attributes[:dimensions]) || []
51
51
  @dimensions.delete_if(&:empty?)
52
52
  @filter = attributes && attributes[:filter] ? attributes[:filter] : {}
53
53
  @filter.keys.dup.each { |k| @filter[k] = Array(@filter[k]) }
@@ -1,3 +1,3 @@
1
1
  module SimpleDrilldown
2
- VERSION = '0.9.11'
2
+ VERSION = '0.11.0'
3
3
  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.9.11
4
+ version: 0.11.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: 2021-06-16 00:00:00.000000000 Z
11
+ date: 2022-02-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: caxlsx_rails
@@ -137,10 +137,12 @@ files:
137
137
  - config/locales/en.yml
138
138
  - config/locales/nb.yml
139
139
  - config/routes.rb
140
- - lib/generators/drilldown_controller/USAGE
141
- - lib/generators/drilldown_controller/drilldown_controller_generator.rb
142
- - lib/generators/drilldown_controller/templates/drilldown_controller.rb.erb
143
- - lib/generators/drilldown_controller/templates/drilldown_controller_test.rb.erb
140
+ - lib/generators/simple_drilldown/controller/USAGE
141
+ - lib/generators/simple_drilldown/controller/controller_generator.rb
142
+ - lib/generators/simple_drilldown/controller/templates/drilldown_controller.rb.erb
143
+ - lib/generators/simple_drilldown/controller/templates/drilldown_controller_test.rb.erb
144
+ - lib/generators/simple_drilldown/views/USAGE
145
+ - lib/generators/simple_drilldown/views/views_generator.rb
144
146
  - lib/simple_drilldown.rb
145
147
  - lib/simple_drilldown/changes.rb
146
148
  - lib/simple_drilldown/controller.rb
@@ -170,7 +172,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
170
172
  - !ruby/object:Gem::Version
171
173
  version: '0'
172
174
  requirements: []
173
- rubygems_version: 3.2.15
175
+ rubygems_version: 3.3.3
174
176
  signing_key:
175
177
  specification_version: 4
176
178
  summary: Simple data warehouse and drilldown.
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class DrilldownControllerGenerator < Rails::Generators::NamedBase
4
- source_root File.expand_path('templates', __dir__)
5
-
6
- def copy_drilldown_controller_file
7
- template 'drilldown_controller.rb.erb', "app/controllers/#{file_name}_drilldown_controller.rb"
8
- template 'drilldown_controller_test.rb.erb', "test/controllers/#{file_name}_drilldown_controller_test.rb"
9
- route "draw_drilldown :#{singular_name}"
10
- end
11
- end