reports_kit 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 50df5df0e40d9cd127c03bacec3905c401be05ab
4
- data.tar.gz: 071d750fe875bcdaa4308fde9e6bf280b18c5d3e
3
+ metadata.gz: e12a4b95211ec84a8662237e268dfacfcd23978a
4
+ data.tar.gz: c5ec6f7f3f4e8bd9613764e8cd74108971255c26
5
5
  SHA512:
6
- metadata.gz: a6fbfb97c8e5f30a23d1260c73046e5f1e19941b0cdaad796ae490c8ebcbf73eeacc3eb3cfc1cd974f80e58b7c31e56d7366e3311e6af9146da055a64c410f25
7
- data.tar.gz: 57c6cdba6764b876efbe81d85f98285c5945b85f0571d8fa715806f2210b94b317698b06a957171ef78ea15fc23d2c21e904eb6f2f250e9036270f5217d26fd7
6
+ metadata.gz: 94b293476548bdd6ad1bed10018e4889f4d28a56b59490059274777fcd608790399a2f835b6f858d9f4075fd96c9accfe382d6fa4e9474079a827008fb157b0f
7
+ data.tar.gz: fd582ab216f799db4dbf3c0c197b95f5ebe155b55fa9bcc17bfbb15adcdf79dc22f85d999109187d02d8678b045fcc57846d8aa0748d8c1830d8e7e030662e3c
data/README.md CHANGED
@@ -2,117 +2,20 @@ ReportsKit
2
2
  =====
3
3
  [![Build Status](https://travis-ci.org/tombenner/reports_kit.svg?branch=master)](https://travis-ci.org/tombenner/reports_kit)
4
4
 
5
- ReportsKit lets you easily create beautiful charts with customizable, interactive filters.
5
+ ReportsKit lets you easily create beautiful, interactive charts and tables.
6
6
 
7
- For interactive examples, see [reportskit.co](https://www.reportskit.co/).
8
-
9
- ---
7
+ For examples and documentation, see [reportskit.co](https://www.reportskit.co/).
10
8
 
11
9
  [<img src="docs/images/demo.gif?raw=true" width="700" />](docs/images/demo.gif?raw=true)
12
10
 
13
- [<img src="docs/images/demo_area.png?raw=true" width="425" />](docs/images/demo_area.png?raw=true)
14
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
15
- [<img src="docs/images/demo_dashed_line.png?raw=true" width="425" />](docs/images/demo_dashed_line.png?raw=true)
16
-
17
- [<img src="docs/images/demo_horizontal_stacked.png?raw=true" width="425" />](docs/images/demo_horizontal_stacked.png?raw=true)
18
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
19
- [<img src="docs/images/demo_legend.png?raw=true" width="425" />](docs/images/demo_legend.png?raw=true)
20
-
21
- [<img src="docs/images/demo_multiautocomplete.png?raw=true" width="425" />](docs/images/demo_multiautocomplete.png?raw=true)
22
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
23
- [<img src="docs/images/demo_radar.png?raw=true" width="230" />](docs/images/demo_radar.png?raw=true)
24
-
25
- ---
26
-
27
- 1. **Quick setup** - Install ReportsKit and create your first chart in less than one minute using just ~5 lines of code.
28
- 1. **Simple chart configuration** - Create charts using your existing Rails models. ReportsKit examines the column types and associations to understand how to render the chart.
29
- 1. **Powerful results** - To see what ReportsKit can create with minimal code, see [reportskit.co](https://www.reportskit.co/).
30
-
31
11
  Resources
32
12
  ---------
33
13
 
34
- * [Installation](#installation)
35
- * [Quick Start](#quick-start)
36
- * [Examples](https://www.reportskit.co/)
37
- * [Documentation](docs)
38
-
39
- Installation
40
- ------------
41
-
42
- In `Gemfile`:
43
- ```ruby
44
- gem 'reports_kit'
45
- ```
46
-
47
- In `app/assets/stylesheets/application.css.scss`:
48
- ```scss
49
- *= require reports_kit/application
50
- ```
51
-
52
- In `app/assets/javascripts/application.js`:
53
- ```js
54
- //= require reports_kit/application
55
- ```
56
-
57
- In `config/routes.rb`:
58
- ```ruby
59
- Rails.application.routes.draw do
60
- mount ReportsKit::Engine, at: '/'
61
- # ...
62
- end
63
- ```
64
-
65
- Quick Start
66
- -----------
67
-
68
- After installation, you can create your first chart with just a YAML file and a single line in any view.
69
-
70
- Configure the chart in the YAML file:
71
-
72
- `config/reports_kit/reports/my_users.yml`
73
- ```yaml
74
- measure: user
75
- dimensions:
76
- - created_at
77
- ```
78
-
79
- Then pass that filename to `render_report` in a view:
80
-
81
- `app/views/users/index.html.haml`
82
- ```haml
83
- = render_report 'my_users'
84
- ```
85
-
86
- You're done! `render_report` will render the following chart:
87
-
88
- [<img src="docs/images/users_by_created_at.png?raw=true" width="500" />](docs/images/users_by_created_at.png?raw=true)
89
-
90
- ### Form Controls
91
-
92
- You can add a date range form control to the above chart with a single line, using one of ReportsKit's form helpers:
93
-
94
- `app/views/users/index.html.haml`
95
- ```haml
96
- = render_report 'my_users' do |f|
97
- = f.date_range :created_at
98
- ```
99
-
100
- [<img src="docs/images/users_by_created_at_with_filter.png?raw=true" width="500" />](docs/images/users_by_created_at_with_filter.png?raw=true)
101
-
102
- Many other form controls are available; see [Filters](docs/filters.md) for more.
103
-
104
- ### How It Works
105
-
106
- In the Quick Start chart, `measure: user` tells ReportsKit to count the number of `User` records, and `dimensions: ['created_at']` tells it to group by the week of the `created_at` column. Since `created_at` is a `datetime` column, ReportsKit knows that it should group the counts by week (the granularity is configurable), sort them chronologically, and add in zeros for any missing weeks.
107
-
108
- ReportsKit infers sane defaults from your ActiveRecord model configurations. If there was a `belongs_to :company` association on `User` and you used `dimensions: ['company']`, then ReportsKit would count users grouped by the `company_id` column and show company names on the x-axis.
109
-
110
- If you need more customization (e.g. custom filters, custom dimensions, custom aggregation functions, custom orders, aggregations of aggregations, etc), ReportsKit is very flexible and powerful and supports all of these with a simple syntax. It lets you use SQL, too.
111
-
112
- To learn how to use more of ReportsKit's features, check out the following resources:
113
-
114
- * [Examples](https://www.reportskit.co/)
115
- * [Documentation](docs)
14
+ * [Documentation](https://www.reportskit.co/)
15
+ * [Getting Started](https://www.reportskit.co/categories/getting_started)
16
+ * [Data Examples](https://www.reportskit.co/categories/data)
17
+ * [Visualization Examples](https://www.reportskit.co/categories/visualization)
18
+ * [How It Works](https://www.reportskit.co/categories/getting_started/subcategories/how_it_works)
116
19
 
117
20
  Testing
118
21
  -------
@@ -37,15 +37,22 @@ ReportsKit.Table = (function(options) {
37
37
  }
38
38
  self.table.show().fadeTo(300, 1);
39
39
 
40
- var rowAggregationsCount = self.rowAggregationsCount(reportOptions);
41
- var rowAggregationsStartIndex = rowAggregationsCount ? (tableData.length - rowAggregationsCount) : null;
40
+ var rowsCount = tableData.length;
41
+
42
+ var hasHead = typeof reportOptions.head_rows_count !== 'undefined';
43
+ var hasFoot = typeof reportOptions.foot_rows_count !== 'undefined';
44
+ var headRowStartIndex = hasHead ? 0 : 0;
45
+ var headRowEndIndex = hasHead ? reportOptions.head_rows_count - 1 : 0;
46
+ var footRowStartIndex = hasFoot ? rowsCount - reportOptions.foot_rows_count : null;
47
+ var footRowEndIndex = hasFoot ? rowsCount - 1 : null;
48
+
42
49
  var html = '';
43
- for(var i = 0; i < tableData.length; i++) {
44
- if (i == 0) {
50
+ for(var i = 0; i < rowsCount; i++) {
51
+ if (i === headRowStartIndex) {
45
52
  html += '<thead><tr>';
46
- } else if (i == 1) {
53
+ } else if (i === (headRowEndIndex + 1)) {
47
54
  html += '<tbody><tr>';
48
- } else if (rowAggregationsCount && i == rowAggregationsStartIndex) {
55
+ } else if (i === footRowStartIndex) {
49
56
  html += '<tfoot><tr>';
50
57
  } else {
51
58
  html += '<tr>';
@@ -59,12 +66,12 @@ ReportsKit.Table = (function(options) {
59
66
  }
60
67
  }
61
68
 
62
- if (i == 0) {
69
+ if (i === headRowEndIndex) {
63
70
  html += '</tr></thead>';
64
- } else if (i == tableData.length && rowAggregationsCount) {
65
- html += '</tfoot></tbody>';
66
- } else if (i == tableData.length) {
71
+ } else if (i === (footRowStartIndex - 1)) {
67
72
  html += '</tr></tbody>';
73
+ } else if (i === footRowEndIndex) {
74
+ html += '</tfoot></tbody>';
68
75
  } else {
69
76
  html += '</tr>';
70
77
  }
@@ -74,19 +81,6 @@ ReportsKit.Table = (function(options) {
74
81
  });
75
82
  };
76
83
 
77
- self.rowAggregationsCount = function(reportOptions) {
78
- if (!reportOptions.aggregations) {
79
- return 0;
80
- };
81
- var rowAggregationsCount = 0;
82
- for(var i = 0; i < reportOptions.aggregations.length; i++) {
83
- if (reportOptions.aggregations[i].from === 'columns') {
84
- rowAggregationsCount += 1;
85
- }
86
- }
87
- return rowAggregationsCount;
88
- };
89
-
90
84
  self.initialize(options);
91
85
 
92
86
  return self;
@@ -28,3 +28,6 @@
28
28
  content: "\25BC"
29
29
  .headerSortDown::after
30
30
  content: "\25B2"
31
+ .reports_kit_actions
32
+ margin-top: 12px
33
+ text-align: right
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- reports_kit (0.2.0)
4
+ reports_kit (0.3.1)
5
5
  rails (>= 3)
6
6
  spreadsheet (>= 1.1)
7
7
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- reports_kit (0.2.0)
4
+ reports_kit (0.3.1)
5
5
  rails (>= 3)
6
6
  spreadsheet (>= 1.1)
7
7
 
@@ -5,12 +5,13 @@ require 'reports_kit/cache'
5
5
  require 'reports_kit/configuration'
6
6
  require 'reports_kit/engine'
7
7
  require 'reports_kit/entity'
8
+ require 'reports_kit/report_builder'
9
+ require 'reports_kit/form_builder'
8
10
  require 'reports_kit/helper'
9
11
  require 'reports_kit/model'
10
12
  require 'reports_kit/model_configuration'
11
13
  require 'reports_kit/order'
12
14
  require 'reports_kit/relative_time'
13
- require 'reports_kit/report_builder'
14
15
  require 'reports_kit/resources_controller'
15
16
  require 'reports_kit/reports_controller'
16
17
  require 'reports_kit/value'
@@ -1,7 +1,8 @@
1
1
  module ReportsKit
2
2
  class Configuration
3
- attr_accessor :cache_duration, :cache_store, :context_record_method, :custom_methods, :default_dimension_limit,
4
- :default_properties, :first_day_of_week, :properties_method, :report_filename_method, :use_concurrent_queries
3
+ attr_accessor :autocomplete_results_method, :cache_duration, :cache_store, :context_record_method, :custom_methods,
4
+ :default_dimension_limit, :default_properties, :first_day_of_week, :properties_method, :report_filename_method,
5
+ :use_concurrent_queries
5
6
 
6
7
  DEFAULT_PROPERTIES_METHOD = lambda do |env|
7
8
  path = Rails.root.join('config', 'reports_kit', 'reports', "#{report_key}.yml")
@@ -9,6 +10,7 @@ module ReportsKit
9
10
  end
10
11
 
11
12
  def initialize
13
+ self.autocomplete_results_method = nil
12
14
  self.cache_duration = 5.minutes
13
15
  self.cache_store = nil
14
16
  self.context_record_method = nil
@@ -0,0 +1,95 @@
1
+ module ReportsKit
2
+ class FormBuilder
3
+ include ActionView::Helpers
4
+
5
+ DEFAULT_DATE_RANGE_VALUE = ['-2M', 'now']
6
+
7
+ attr_accessor :properties, :additional_params
8
+
9
+ def initialize(properties, additional_params: nil)
10
+ self.properties = properties.deep_symbolize_keys
11
+ self.additional_params = additional_params
12
+ end
13
+
14
+ def check_box(filter_key, options = {})
15
+ filter = validate_filter!(filter_key)
16
+ checked = filter.normalized_properties[:criteria][:value] == 'true'
17
+ check_box_tag(filter_key, '1', checked, options)
18
+ end
19
+
20
+ def date_range(filter_key, options = {})
21
+ filter = validate_filter!(filter_key)
22
+ defaults = { class: 'form-control input-sm date_range_picker' }
23
+ options = defaults.deep_merge(options)
24
+ value = filter.normalized_properties[:criteria][:value].presence
25
+ value ||= default_date_range_value
26
+ text_field_tag(filter_key, value, options)
27
+ end
28
+
29
+ def multi_autocomplete(filter_key, options = {})
30
+ validate_filter!(filter_key)
31
+ filter = series_filters.find { |f| f.key == filter_key.to_s }
32
+ reports_kit_path = Rails.application.routes.url_helpers.reports_kit_path
33
+ path = "#{reports_kit_path}reports_kit/resources/measures/#{filter.series.key}/filters/#{filter_key}/autocomplete?"
34
+ path += additional_params.to_query if additional_params.present?
35
+ scope = options.delete(:scope)
36
+ params = {}
37
+ params[:scope] = scope if scope.present?
38
+
39
+ defaults = {
40
+ class: 'form-control input-sm select2',
41
+ multiple: 'multiple',
42
+ data: {
43
+ placeholder: options[:placeholder],
44
+ path: path,
45
+ params: params
46
+ }
47
+ }
48
+ options = defaults.deep_merge(options)
49
+ select_tag(filter_key, nil, options)
50
+ end
51
+
52
+ def string_filter(filter_key, options = {})
53
+ filter = validate_filter!(filter_key)
54
+ defaults = { class: 'form-control input-sm' }
55
+ options = defaults.deep_merge(options)
56
+ text_field_tag(filter_key, filter.normalized_properties[:criteria][:value], options)
57
+ end
58
+
59
+ private
60
+
61
+ def validate_filter!(filter_key)
62
+ filter_key = filter_key.to_s
63
+ filter = filters.find { |f| f.key == filter_key }
64
+ raise ArgumentError.new("A filter with key '#{filter_key}' is not configured in this report") unless filter
65
+ filter
66
+ end
67
+
68
+ def filters
69
+ ui_filters + series_filters
70
+ end
71
+
72
+ def series_filters
73
+ serieses.map(&:filters).flatten
74
+ end
75
+
76
+ def ui_filters
77
+ return [] if properties[:ui_filters].blank?
78
+ properties[:ui_filters].map do |ui_filter_properties|
79
+ Reports::Filter.new(ui_filter_properties)
80
+ end
81
+ end
82
+
83
+ def serieses
84
+ Reports::Series.new_from_properties!(properties, context_record: nil)
85
+ end
86
+
87
+ def default_date_range_value
88
+ @default_date_range_value ||= begin
89
+ start_date = Reports::Data::Utils.format_time_value(DEFAULT_DATE_RANGE_VALUE[0])
90
+ end_date = Reports::Data::Utils.format_time_value(DEFAULT_DATE_RANGE_VALUE[1])
91
+ [start_date, Reports::FilterTypes::Datetime::SEPARATOR, end_date].join(' ')
92
+ end
93
+ end
94
+ end
95
+ end
@@ -1,66 +1,34 @@
1
1
  module ReportsKit
2
2
  module Helper
3
- ACTION_KEYS_METHODS = {
4
- 'export_csv' => :export_csv_element,
5
- 'export_xls' => :export_xls_element
6
- }
7
-
8
3
  def render_report(report_params, context_params: {}, actions: %w(export_csv export_xls), js_report_class: 'Report', &block)
9
4
  report_params = { key: report_params } if report_params.is_a?(String)
10
- additional_params = { context_params: context_params, report_params: report_params }
11
- params.merge!(additional_params)
12
- properties = instance_eval(&ReportsKit.configuration.properties_method)
13
- properties = properties.deep_symbolize_keys
14
- builder = ReportsKit::ReportBuilder.new(properties, additional_params: additional_params)
15
- path = reports_kit.reports_kit_reports_path({ format: 'json' }.merge(additional_params))
16
- data = { properties: properties.slice(:format), path: path, report_class: js_report_class }
17
- content_tag :div, nil, class: 'reports_kit_report form-inline', data: data do
18
- elements = []
19
- if block_given?
20
- elements << form_tag(path, method: 'get', class: 'reports_kit_report_form') do
21
- capture(builder, &block)
22
- end
23
- end
24
- elements << content_tag(:div, nil, class: 'reports_kit_visualization')
25
- action_elements = generate_action_elements(actions, additional_params)
26
- if action_elements
27
- elements << content_tag(:div, nil, class: 'reports_kit_actions') do
28
- action_elements.map { |element| concat(element) }
29
- end
30
- end
31
- elements.join.html_safe
5
+ params.merge!(context_params: context_params, report_params: report_params)
6
+ properties = instance_eval(&ReportsKit.configuration.properties_method).deep_symbolize_keys
7
+ builder = ReportBuilder.new(
8
+ report_params: report_params,
9
+ context_params: context_params,
10
+ actions: actions,
11
+ js_report_class: js_report_class,
12
+ properties: properties,
13
+ view_context: self,
14
+ block: block
15
+ )
16
+ capture do
17
+ capture(builder, &block) if block
18
+ builder.render
32
19
  end
33
20
  end
34
21
 
35
- private
36
-
37
- def report_key
38
- params[:report_params][:key]
22
+ def context_params
23
+ params[:context_params]
39
24
  end
40
25
 
41
- def generate_action_elements(actions, additional_params)
42
- return if actions.blank?
43
- actions.map do |action|
44
- element_method = ACTION_KEYS_METHODS[action]
45
- raise ArgumentError.new("Invalid action: #{action}") unless element_method
46
- send(element_method, additional_params)
47
- end
26
+ def report_params
27
+ params[:report_params]
48
28
  end
49
29
 
50
- def export_csv_element(additional_params)
51
- data = {
52
- role: 'reports_kit_export_button',
53
- path: reports_kit.reports_kit_reports_path({ format: 'csv' }.merge(additional_params))
54
- }
55
- link_to('Download CSV', '#', class: 'btn btn-primary', data: data)
56
- end
57
-
58
- def export_xls_element(additional_params)
59
- data = {
60
- role: 'reports_kit_export_button',
61
- path: reports_kit.reports_kit_reports_path({ format: 'xls' }.merge(additional_params))
62
- }
63
- link_to('Download Excel', '#', class: 'btn btn-primary', data: data)
30
+ def report_key
31
+ report_params[:key]
64
32
  end
65
33
  end
66
34
  end
@@ -2,93 +2,85 @@ module ReportsKit
2
2
  class ReportBuilder
3
3
  include ActionView::Helpers
4
4
 
5
- DEFAULT_DATE_RANGE_VALUE = ['-2M', 'now']
5
+ attr_accessor :report_params, :context_params, :additional_params, :actions, :js_report_class, :properties, :view_context, :block, :form_builder
6
6
 
7
- attr_accessor :properties, :additional_params
7
+ ACTION_KEYS_METHODS = {
8
+ 'export_csv' => :export_csv_button,
9
+ 'export_xls' => :export_xls_button
10
+ }
8
11
 
9
- def initialize(properties, additional_params: nil)
10
- self.properties = properties.deep_symbolize_keys
11
- self.additional_params = additional_params
12
+ def initialize(report_params:, context_params: {}, actions: %w(export_csv export_xls), js_report_class: 'Report', properties:, view_context:, block: nil)
13
+ self.report_params = report_params.is_a?(String) ? { key: report_params } : report_params
14
+ self.context_params = context_params
15
+ self.additional_params = { context_params: context_params, report_params: self.report_params }
16
+ self.actions = actions
17
+ self.js_report_class = js_report_class
18
+ self.view_context = view_context
19
+ self.block = block
20
+ self.properties = properties#view_context.instance_eval(&ReportsKit.configuration.properties_method).deep_symbolize_keys
21
+ self.form_builder = ReportsKit::FormBuilder.new(properties, additional_params: additional_params)
12
22
  end
13
23
 
14
- def check_box(filter_key, options = {})
15
- filter = validate_filter!(filter_key)
16
- checked = filter.normalized_properties[:criteria][:value] == 'true'
17
- check_box_tag(filter_key, '1', checked, options)
24
+ def render
25
+ data = { properties: properties.slice(:format), path: reports_data_path, report_class: js_report_class }
26
+ view_context.content_tag :div, nil, class: 'reports_kit_report form-inline', data: data do
27
+ elements = []
28
+ elements << view_context.capture(self, &block) if block
29
+ elements << view_context.content_tag(:div, nil, class: 'reports_kit_visualization')
30
+ elements << action_elements_container
31
+ elements.compact.join.html_safe
32
+ end
18
33
  end
19
34
 
20
- def date_range(filter_key, options = {})
21
- filter = validate_filter!(filter_key)
22
- defaults = { class: 'form-control input-sm date_range_picker' }
23
- options = defaults.deep_merge(options)
24
- value = filter.normalized_properties[:criteria][:value].presence
25
- value ||= default_date_range_value
26
- text_field_tag(filter_key, value, options)
35
+ def form(&block)
36
+ raise ArgumentError.new('No block given for ReportBuilder#form') unless block
37
+ view_context.form_tag(reports_data_path, method: 'get', class: 'reports_kit_report_form') do
38
+ view_context.capture(form_builder, &block)
39
+ end
27
40
  end
28
41
 
29
- def multi_autocomplete(filter_key, options = {})
30
- validate_filter!(filter_key)
31
- filter = series_filters.find { |f| f.key == filter_key.to_s }
32
- reports_kit_path = Rails.application.routes.url_helpers.reports_kit_path
33
- path = "#{reports_kit_path}reports_kit/resources/measures/#{filter.series.key}/filters/#{filter_key}/autocomplete?"
34
- path += additional_params.to_query if additional_params.present?
35
- scope = options.delete(:scope)
36
- params = {}
37
- params[:scope] = scope if scope.present?
38
-
39
- defaults = {
40
- class: 'form-control input-sm select2',
41
- multiple: 'multiple',
42
- data: {
43
- placeholder: options[:placeholder],
44
- path: path,
45
- params: params
46
- }
47
- }
48
- options = defaults.deep_merge(options)
49
- select_tag(filter_key, nil, options)
42
+ def export_csv_button(text='Download CSV', options = {}, &block)
43
+ export_button(text, 'csv', options, &block)
50
44
  end
51
45
 
52
- def string_filter(filter_key, options = {})
53
- filter = validate_filter!(filter_key)
54
- defaults = { class: 'form-control input-sm' }
55
- options = defaults.deep_merge(options)
56
- text_field_tag(filter_key, filter.normalized_properties[:criteria][:value], options)
46
+ def export_xls_button(text='Download Excel', options = {}, &block)
47
+ export_button(text, 'xls', options, &block)
57
48
  end
58
49
 
59
- private
60
-
61
- def validate_filter!(filter_key)
62
- filter_key = filter_key.to_s
63
- filter = filters.find { |f| f.key == filter_key }
64
- raise ArgumentError.new("A filter with key '#{filter_key}' is not configured in this report") unless filter
65
- filter
50
+ def export_button(text, format, options, &block)
51
+ data = {
52
+ role: 'reports_kit_export_button',
53
+ path: view_context.reports_kit.reports_kit_reports_path({ format: format }.merge(additional_params))
54
+ }
55
+ options = { class: 'btn btn-primary', data: data }.merge(options)
56
+ if block_given?
57
+ view_context.link_to('#', options, &block)
58
+ else
59
+ view_context.link_to(text, '#', options)
60
+ end
66
61
  end
67
62
 
68
- def filters
69
- ui_filters + series_filters
70
- end
63
+ private
71
64
 
72
- def series_filters
73
- serieses.map(&:filters).flatten
65
+ def reports_data_path
66
+ @reports_data_path ||= view_context.reports_kit.reports_kit_reports_path({ format: 'json' }.merge(additional_params))
74
67
  end
75
68
 
76
- def ui_filters
77
- return [] if properties[:ui_filters].blank?
78
- properties[:ui_filters].map do |ui_filter_properties|
79
- Reports::Filter.new(ui_filter_properties)
69
+ def action_elements_container
70
+ return if action_elements.blank?
71
+ view_context.content_tag(:div, nil, class: 'reports_kit_actions') do
72
+ action_elements.map { |element| view_context.concat(element) }
80
73
  end
81
74
  end
82
75
 
83
- def serieses
84
- Reports::Series.new_from_properties!(properties, context_record: nil)
85
- end
86
-
87
- def default_date_range_value
88
- @default_date_range_value ||= begin
89
- start_date = Reports::Data::Utils.format_time_value(DEFAULT_DATE_RANGE_VALUE[0])
90
- end_date = Reports::Data::Utils.format_time_value(DEFAULT_DATE_RANGE_VALUE[1])
91
- [start_date, Reports::FilterTypes::Datetime::SEPARATOR, end_date].join(' ')
76
+ def action_elements
77
+ @action_elements ||= begin
78
+ return if actions.blank?
79
+ actions.map do |action|
80
+ element_method = ACTION_KEYS_METHODS[action]
81
+ raise ArgumentError.new("Invalid action: #{action}") unless element_method
82
+ send(element_method)
83
+ end.compact
92
84
  end
93
85
  end
94
86
  end
@@ -91,7 +91,14 @@ module ReportsKit
91
91
  end
92
92
 
93
93
  def report_options
94
- properties[:report_options]
94
+ report_options = properties[:report_options] || {}
95
+ head_rows_count = report_options[:head_rows_count]
96
+ foot_rows_count = report_options[:foot_rows_count]
97
+ foot_rows_count ||= report_options[:aggregations].count { |config| config[:from] == 'rows' } if report_options[:aggregations]
98
+
99
+ report_options[:head_rows_count] = head_rows_count if head_rows_count && head_rows_count > 0
100
+ report_options[:foot_rows_count] = foot_rows_count if foot_rows_count && foot_rows_count > 0
101
+ report_options.presence
95
102
  end
96
103
 
97
104
  def data_format_method
@@ -12,6 +12,7 @@ module ReportsKit
12
12
 
13
13
  def perform
14
14
  raise ArgumentError.new("Could not find a model for filter_key: '#{filter_key}'") unless model
15
+ return autocomplete_results_method.call(params: params, context_record: context_record, relation: relation) if autocomplete_results_method
15
16
  results = relation
16
17
  results = results.public_send(scope) if scope
17
18
  results = results.limit(10_000)
@@ -23,6 +24,10 @@ module ReportsKit
23
24
 
24
25
  private
25
26
 
27
+ def autocomplete_results_method
28
+ ReportsKit.configuration.autocomplete_results_method
29
+ end
30
+
26
31
  def relation
27
32
  if context_record
28
33
  context_record.public_send(model.name.tableize)
@@ -26,6 +26,19 @@ module ReportsKit
26
26
  end
27
27
  end
28
28
 
29
+ def report_params
30
+ params[:report_params]
31
+ end
32
+
33
+ def context_params
34
+ params[:context_params]
35
+ end
36
+
37
+ def report_key
38
+ raise ArgumentError.new('Blank report_params') if report_params.blank?
39
+ report_params[:key]
40
+ end
41
+
29
42
  private
30
43
 
31
44
  def report_filename
@@ -38,10 +51,6 @@ module ReportsKit
38
51
  Reports::Data::Generate.new(properties, context_record: context_record).perform
39
52
  end
40
53
 
41
- def report_key
42
- params[:report_params][:key]
43
- end
44
-
45
54
  def properties
46
55
  @properties ||= begin
47
56
  properties_method = ReportsKit.configuration.properties_method
@@ -1,3 +1,3 @@
1
1
  module ReportsKit
2
- VERSION = '0.3.0'
2
+ VERSION = '0.3.1'
3
3
  end
@@ -130,6 +130,32 @@
130
130
  - from: rows
131
131
  operator: sum
132
132
  label: Total
133
+ - series:
134
+ - measure:
135
+ key: issue
136
+ name: Repo Issues
137
+ dimensions:
138
+ - key: repo
139
+ label:
140
+ - measure: label
141
+ dimensions:
142
+ - repo
143
+ format: table
144
+ report_options:
145
+ head_rows_count: 2
146
+ - series:
147
+ - measure:
148
+ key: issue
149
+ name: Repo Issues
150
+ dimensions:
151
+ - key: repo
152
+ label:
153
+ - measure: label
154
+ dimensions:
155
+ - repo
156
+ format: table
157
+ report_options:
158
+ foot_rows_count: 3
133
159
  - series:
134
160
  measure: label
135
161
  dimensions:
@@ -425,6 +425,7 @@
425
425
  - :from: rows
426
426
  :operator: sum
427
427
  :label: Total
428
+ :foot_rows_count: 1
428
429
  :table_data:
429
430
  - -
430
431
  - Repo Issues
@@ -447,6 +448,7 @@
447
448
  - :from: rows
448
449
  :operator: sum
449
450
  :label: Total
451
+ :foot_rows_count: 1
450
452
  :table_data:
451
453
  - -
452
454
  - Repo Issues
@@ -464,6 +466,32 @@
464
466
  - 2
465
467
  - 3
466
468
  - 5
469
+ - :type: table
470
+ :report_options:
471
+ :head_rows_count: 2
472
+ :table_data:
473
+ - -
474
+ - Repo Issues
475
+ - Labels
476
+ - - foo/bar1
477
+ - 2
478
+ - 1
479
+ - - foo/bar2
480
+ - 0
481
+ - 2
482
+ - :type: table
483
+ :report_options:
484
+ :foot_rows_count: 3
485
+ :table_data:
486
+ - -
487
+ - Repo Issues
488
+ - Labels
489
+ - - foo/bar1
490
+ - 2
491
+ - 1
492
+ - - foo/bar2
493
+ - 0
494
+ - 2
467
495
  - :chart_data:
468
496
  :labels:
469
497
  - foo/bar1
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ReportsKit::ReportBuilder do
3
+ describe ReportsKit::FormBuilder do
4
4
  subject { described_class.new(properties) }
5
5
 
6
6
  context 'with a datetime dimension' do
@@ -876,7 +876,7 @@ describe ReportsKit::Reports::Data::Generate do
876
876
  end
877
877
  end
878
878
 
879
- describe 'composite aggregations' do
879
+ describe 'composite series' do
880
880
  context 'with two series' do
881
881
  let(:properties) do
882
882
  {
@@ -1114,7 +1114,7 @@ describe ReportsKit::Reports::Data::Generate do
1114
1114
  end
1115
1115
  end
1116
1116
 
1117
- context 'with a nested composite aggregation' do
1117
+ context 'with a nested composite series' do
1118
1118
  let(:properties) do
1119
1119
  {
1120
1120
  series: [
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reports_kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Benner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-08-19 00:00:00.000000000 Z
11
+ date: 2017-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -226,6 +226,7 @@ files:
226
226
  - lib/reports_kit/configuration.rb
227
227
  - lib/reports_kit/engine.rb
228
228
  - lib/reports_kit/entity.rb
229
+ - lib/reports_kit/form_builder.rb
229
230
  - lib/reports_kit/helper.rb
230
231
  - lib/reports_kit/model.rb
231
232
  - lib/reports_kit/model_configuration.rb
@@ -274,8 +275,8 @@ files:
274
275
  - spec/factories/tag_factory.rb
275
276
  - spec/fixtures/generate_inputs.yml
276
277
  - spec/fixtures/generate_outputs.yml
278
+ - spec/reports_kit/form_builder_spec.rb
277
279
  - spec/reports_kit/relative_time_spec.rb
278
- - spec/reports_kit/report_builder_spec.rb
279
280
  - spec/reports_kit/reports/data/generate_spec.rb
280
281
  - spec/reports_kit/reports/dimension_with_series_spec.rb
281
282
  - spec/reports_kit/reports/filter_with_series_spec.rb