reports_kit 0.1.0 → 0.2.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.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -5
  3. data/app/assets/javascripts/reports_kit/lib/chart.js +33 -8
  4. data/app/assets/javascripts/reports_kit/lib/report.js +27 -26
  5. data/app/assets/javascripts/reports_kit/lib/table.js +58 -0
  6. data/app/assets/javascripts/reports_kit/vendor/jquery.tablesorter.min.js +4 -0
  7. data/app/assets/stylesheets/reports_kit/reports.css.sass +20 -0
  8. data/config/initializers/mime_types.rb +1 -0
  9. data/docs/dimensions.md +34 -26
  10. data/docs/display_options.md +15 -12
  11. data/docs/filters.md +2 -2
  12. data/docs/measures.md +4 -3
  13. data/gemfiles/mysql.gemfile.lock +14 -1
  14. data/gemfiles/postgresql.gemfile.lock +14 -1
  15. data/lib/reports_kit.rb +15 -0
  16. data/lib/reports_kit/cache.rb +37 -0
  17. data/lib/reports_kit/configuration.rb +13 -1
  18. data/lib/reports_kit/helper.rb +54 -3
  19. data/lib/reports_kit/model_configuration.rb +6 -1
  20. data/lib/reports_kit/order.rb +33 -0
  21. data/lib/reports_kit/relative_time.rb +42 -0
  22. data/lib/reports_kit/report_builder.rb +34 -15
  23. data/lib/reports_kit/reports/abstract_measure.rb +9 -0
  24. data/lib/reports_kit/reports/adapters/mysql.rb +8 -1
  25. data/lib/reports_kit/reports/adapters/postgresql.rb +8 -1
  26. data/lib/reports_kit/reports/composite_measure.rb +43 -0
  27. data/lib/reports_kit/reports/data/chart_options.rb +5 -0
  28. data/lib/reports_kit/reports/data/composite_aggregation.rb +96 -0
  29. data/lib/reports_kit/reports/data/entity.rb +7 -0
  30. data/lib/reports_kit/reports/data/format_one_dimension.rb +120 -0
  31. data/lib/reports_kit/reports/data/format_two_dimensions.rb +141 -0
  32. data/lib/reports_kit/reports/data/generate.rb +72 -25
  33. data/lib/reports_kit/reports/data/generate_for_properties.rb +75 -0
  34. data/lib/reports_kit/reports/data/one_dimension.rb +15 -49
  35. data/lib/reports_kit/reports/data/populate_one_dimension.rb +36 -0
  36. data/lib/reports_kit/reports/data/populate_two_dimensions.rb +104 -0
  37. data/lib/reports_kit/reports/data/two_dimensions.rb +15 -110
  38. data/lib/reports_kit/reports/data/utils.rb +77 -12
  39. data/lib/reports_kit/reports/data/value.rb +7 -0
  40. data/lib/reports_kit/reports/dimension.rb +4 -110
  41. data/lib/reports_kit/reports/dimension_with_measure.rb +137 -0
  42. data/lib/reports_kit/reports/filter.rb +5 -64
  43. data/lib/reports_kit/reports/filter_types/base.rb +1 -1
  44. data/lib/reports_kit/reports/filter_types/boolean.rb +9 -7
  45. data/lib/reports_kit/reports/filter_types/datetime.rb +7 -5
  46. data/lib/reports_kit/reports/filter_types/number.rb +2 -0
  47. data/lib/reports_kit/reports/filter_with_measure.rb +84 -0
  48. data/lib/reports_kit/reports/generate_autocomplete_results.rb +1 -1
  49. data/lib/reports_kit/reports/inferrable_configuration.rb +32 -13
  50. data/lib/reports_kit/reports/measure.rb +48 -12
  51. data/lib/reports_kit/reports_controller.rb +42 -3
  52. data/lib/reports_kit/version.rb +1 -1
  53. data/reports_kit.gemspec +2 -0
  54. data/spec/fixtures/generate_inputs.yml +146 -21
  55. data/spec/fixtures/generate_outputs.yml +768 -17
  56. data/spec/reports_kit/relative_time_spec.rb +29 -0
  57. data/spec/reports_kit/report_builder_spec.rb +28 -0
  58. data/spec/reports_kit/reports/data/generate_spec.rb +614 -27
  59. data/spec/reports_kit/reports/dimension_with_measure_spec.rb +69 -0
  60. data/spec/reports_kit/reports/{filter_spec.rb → filter_with_measure_spec.rb} +4 -3
  61. data/spec/spec_helper.rb +7 -2
  62. data/spec/support/config.rb +11 -0
  63. data/spec/support/helpers.rb +3 -3
  64. data/spec/support/models/issue.rb +7 -0
  65. metadata +53 -4
  66. data/spec/reports_kit/reports/dimension_spec.rb +0 -54
@@ -60,7 +60,7 @@ measure:
60
60
  filters:
61
61
  - key: is_on_time
62
62
  criteria:
63
- operator: true
63
+ value: true
64
64
  dimensions:
65
65
  - carrier
66
66
  ```
@@ -139,7 +139,7 @@ measure:
139
139
  filters:
140
140
  - key: was_delayed
141
141
  criteria:
142
- operator: true
142
+ value: true
143
143
  dimensions:
144
144
  - carrier
145
145
  ```
@@ -5,8 +5,9 @@ The measure is what is being counted (or aggregated in another way). You can use
5
5
  For example, say we have a `Flight` model with a `flight_at` datetime column. We can chart the number of flights over time:
6
6
 
7
7
  ```yaml
8
- measure: flight
9
- dimensions:
10
- - flight_at
8
+ measure:
9
+ key: flight
10
+ dimensions:
11
+ - flight_at
11
12
  ```
12
13
  [<img src="images/flights_by_flight_at.png?raw=true" width="500" />](images/flights_by_flight_at.png?raw=true)
@@ -1,8 +1,9 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- reports_kit (0.0.4)
4
+ reports_kit (0.2.0)
5
5
  rails (>= 3)
6
+ spreadsheet (>= 1.1)
6
7
 
7
8
  GEM
8
9
  remote: https://rubygems.org/
@@ -50,9 +51,14 @@ GEM
50
51
  thor (>= 0.14.0)
51
52
  arel (8.0.0)
52
53
  builder (3.2.3)
54
+ byebug (2.7.0)
55
+ columnize (~> 0.3)
56
+ debugger-linecache (~> 1.2)
53
57
  coderay (1.1.1)
58
+ columnize (0.9.0)
54
59
  concurrent-ruby (1.0.5)
55
60
  database_cleaner (1.6.1)
61
+ debugger-linecache (1.2.0)
56
62
  diff-lcs (1.3)
57
63
  erubi (1.6.1)
58
64
  factory_girl (4.8.0)
@@ -79,6 +85,9 @@ GEM
79
85
  coderay (~> 1.1.0)
80
86
  method_source (~> 0.8.1)
81
87
  slop (~> 3.4)
88
+ pry-byebug (1.3.3)
89
+ byebug (~> 2.7)
90
+ pry (~> 0.10)
82
91
  rack (2.0.3)
83
92
  rack-test (0.6.3)
84
93
  rack (>= 1.0)
@@ -119,7 +128,10 @@ GEM
119
128
  diff-lcs (>= 1.2.0, < 2.0)
120
129
  rspec-support (~> 3.6.0)
121
130
  rspec-support (3.6.0)
131
+ ruby-ole (1.2.12.1)
122
132
  slop (3.6.0)
133
+ spreadsheet (1.1.4)
134
+ ruby-ole (>= 1.0)
123
135
  sprockets (3.7.1)
124
136
  concurrent-ruby (~> 1.0)
125
137
  rack (> 1, < 3)
@@ -146,6 +158,7 @@ DEPENDENCIES
146
158
  mysql2
147
159
  pg (>= 0.15)
148
160
  pry (~> 0)
161
+ pry-byebug (~> 1)
149
162
  reports_kit!
150
163
  rspec (~> 3)
151
164
  timecop (~> 0)
@@ -1,8 +1,9 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- reports_kit (0.0.4)
4
+ reports_kit (0.2.0)
5
5
  rails (>= 3)
6
+ spreadsheet (>= 1.1)
6
7
 
7
8
  GEM
8
9
  remote: https://rubygems.org/
@@ -50,9 +51,14 @@ GEM
50
51
  thor (>= 0.14.0)
51
52
  arel (8.0.0)
52
53
  builder (3.2.3)
54
+ byebug (2.7.0)
55
+ columnize (~> 0.3)
56
+ debugger-linecache (~> 1.2)
53
57
  coderay (1.1.1)
58
+ columnize (0.9.0)
54
59
  concurrent-ruby (1.0.5)
55
60
  database_cleaner (1.6.1)
61
+ debugger-linecache (1.2.0)
56
62
  diff-lcs (1.3)
57
63
  erubi (1.6.1)
58
64
  factory_girl (4.8.0)
@@ -78,6 +84,9 @@ GEM
78
84
  coderay (~> 1.1.0)
79
85
  method_source (~> 0.8.1)
80
86
  slop (~> 3.4)
87
+ pry-byebug (1.3.3)
88
+ byebug (~> 2.7)
89
+ pry (~> 0.10)
81
90
  rack (2.0.3)
82
91
  rack-test (0.6.3)
83
92
  rack (>= 1.0)
@@ -118,7 +127,10 @@ GEM
118
127
  diff-lcs (>= 1.2.0, < 2.0)
119
128
  rspec-support (~> 3.6.0)
120
129
  rspec-support (3.6.0)
130
+ ruby-ole (1.2.12.1)
121
131
  slop (3.6.0)
132
+ spreadsheet (1.1.4)
133
+ ruby-ole (>= 1.0)
122
134
  sprockets (3.7.1)
123
135
  concurrent-ruby (~> 1.0)
124
136
  rack (> 1, < 3)
@@ -144,6 +156,7 @@ DEPENDENCIES
144
156
  factory_girl (~> 4)
145
157
  pg
146
158
  pry (~> 0)
159
+ pry-byebug (~> 1)
147
160
  reports_kit!
148
161
  rspec (~> 3)
149
162
  timecop (~> 0)
@@ -1,11 +1,14 @@
1
1
  require 'rails/all'
2
2
 
3
3
  require 'reports_kit/base_controller'
4
+ require 'reports_kit/cache'
4
5
  require 'reports_kit/configuration'
5
6
  require 'reports_kit/engine'
6
7
  require 'reports_kit/helper'
7
8
  require 'reports_kit/model'
8
9
  require 'reports_kit/model_configuration'
10
+ require 'reports_kit/order'
11
+ require 'reports_kit/relative_time'
9
12
  require 'reports_kit/report_builder'
10
13
  require 'reports_kit/resources_controller'
11
14
  require 'reports_kit/reports_controller'
@@ -15,10 +18,18 @@ require 'reports_kit/reports/adapters/mysql'
15
18
  require 'reports_kit/reports/adapters/postgresql'
16
19
 
17
20
  require 'reports_kit/reports/data/chart_options'
21
+ require 'reports_kit/reports/data/composite_aggregation'
22
+ require 'reports_kit/reports/data/entity'
23
+ require 'reports_kit/reports/data/format_one_dimension'
24
+ require 'reports_kit/reports/data/format_two_dimensions'
18
25
  require 'reports_kit/reports/data/generate'
26
+ require 'reports_kit/reports/data/generate_for_properties'
19
27
  require 'reports_kit/reports/data/one_dimension'
28
+ require 'reports_kit/reports/data/populate_one_dimension'
29
+ require 'reports_kit/reports/data/populate_two_dimensions'
20
30
  require 'reports_kit/reports/data/two_dimensions'
21
31
  require 'reports_kit/reports/data/utils'
32
+ require 'reports_kit/reports/data/value'
22
33
 
23
34
  require 'reports_kit/reports/filter_types/base'
24
35
  require 'reports_kit/reports/filter_types/boolean'
@@ -27,8 +38,12 @@ require 'reports_kit/reports/filter_types/number'
27
38
  require 'reports_kit/reports/filter_types/records'
28
39
  require 'reports_kit/reports/filter_types/string'
29
40
 
41
+ require 'reports_kit/reports/abstract_measure'
42
+ require 'reports_kit/reports/composite_measure'
30
43
  require 'reports_kit/reports/dimension'
44
+ require 'reports_kit/reports/dimension_with_measure'
31
45
  require 'reports_kit/reports/filter'
46
+ require 'reports_kit/reports/filter_with_measure'
32
47
  require 'reports_kit/reports/generate_autocomplete_results'
33
48
  require 'reports_kit/reports/inferrable_configuration'
34
49
  require 'reports_kit/reports/measure'
@@ -0,0 +1,37 @@
1
+ module ReportsKit
2
+ class Cache
3
+ CACHE_PREFIX = 'reports_kit:reports:'
4
+
5
+ def self.get(properties, context_record)
6
+ return unless store
7
+ key = self.key(properties, context_record)
8
+ json_string = store.get(key)
9
+ return if json_string.blank?
10
+ ActiveSupport::JSON.decode(json_string)
11
+ end
12
+
13
+ def self.set(properties, context_record, data)
14
+ return unless store
15
+ key = self.key(properties, context_record)
16
+ json_string = ActiveSupport::JSON.encode(data)
17
+ store.setex(key, duration, json_string)
18
+ end
19
+
20
+ private
21
+
22
+ def self.key(properties, context_record)
23
+ key = properties.to_json
24
+ key += "#{context_record.class}#{context_record.id}" if context_record
25
+ key = Digest::MD5.hexdigest(key)
26
+ "#{CACHE_PREFIX}#{key}"
27
+ end
28
+
29
+ def self.duration
30
+ @duration ||= ReportsKit.configuration.cache_duration
31
+ end
32
+
33
+ def self.store
34
+ @store ||= ReportsKit.configuration.cache_store
35
+ end
36
+ end
37
+ end
@@ -1,10 +1,22 @@
1
1
  module ReportsKit
2
2
  class Configuration
3
- attr_accessor :context_record_method, :first_day_of_week
3
+ attr_accessor :cache_duration, :cache_store,
4
+ :context_params_method, :context_record_method, :custom_methods, :first_day_of_week
4
5
 
5
6
  def initialize
7
+ self.cache_duration = 5.minutes
8
+ self.cache_store = nil
9
+ self.context_params_method = nil
6
10
  self.context_record_method = nil
11
+ self.custom_methods = {}
7
12
  self.first_day_of_week = :sunday
8
13
  end
14
+
15
+ def custom_method(method_name)
16
+ return if method_name.blank?
17
+ method = custom_methods[method_name.to_sym]
18
+ raise ArgumentError.new("A method named '#{method_name}' is not defined") unless method
19
+ method
20
+ end
9
21
  end
10
22
  end
@@ -1,19 +1,70 @@
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
+
3
8
  def render_report(properties, &block)
4
9
  raise ArgumentError.new('`properties` must be a Hash or String') if properties.blank?
5
10
  if properties.is_a?(String)
6
11
  path = Rails.root.join('config', 'reports_kit', 'reports', "#{properties}.yml")
7
12
  properties = YAML.load_file(path)
8
13
  end
9
- builder = ReportsKit::ReportBuilder.new(properties)
10
- content_tag :div, nil, class: 'reports_kit_report', data: { properties: builder.properties, path: reports_kit_path } do
14
+ builder = ReportsKit::ReportBuilder.new(properties, additional_params: additional_params)
15
+ path = reports_kit.reports_kit_reports_path({ format: 'json' }.merge(additional_params))
16
+ content_tag :div, nil, class: 'reports_kit_report form-inline', data: { properties: builder.properties, path: path } do
17
+ elements = []
11
18
  if block_given?
12
- form_tag reports_kit_path, method: 'get', class: 'reports_kit_report_form form-inline' do
19
+ elements << form_tag(path, method: 'get', class: 'reports_kit_report_form') do
13
20
  capture(builder, &block)
14
21
  end
15
22
  end
23
+ elements << content_tag(:div, nil, class: 'reports_kit_visualization')
24
+ action_elements = action_elements_for_properties(properties)
25
+ if action_elements
26
+ elements << content_tag(:div, nil, class: 'reports_kit_actions') do
27
+ action_elements.map { |element| concat(element) }
28
+ end
29
+ end
30
+ elements.join.html_safe
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def additional_params
37
+ @additional_params ||= begin
38
+ context_params_method = ReportsKit.configuration.context_params_method
39
+ return {} unless context_params_method
40
+ context_params = instance_eval(&context_params_method)
41
+ { context_params: context_params }
16
42
  end
17
43
  end
44
+
45
+ def action_elements_for_properties(properties)
46
+ return if properties['actions'].blank?
47
+ properties['actions'].map do |action|
48
+ element_method = ACTION_KEYS_METHODS[action]
49
+ raise ArgumentError.new("Invalid action: #{action}") unless element_method
50
+ send(element_method)
51
+ end
52
+ end
53
+
54
+ def export_csv_element
55
+ data = {
56
+ role: 'reports_kit_export_button',
57
+ path: reports_kit.reports_kit_reports_path({ format: 'csv' }.merge(additional_params))
58
+ }
59
+ link_to('Download CSV', '#', class: 'btn btn-primary', data: data)
60
+ end
61
+
62
+ def export_xls_element
63
+ data = {
64
+ role: 'reports_kit_export_button',
65
+ path: reports_kit.reports_kit_reports_path({ format: 'xls' }.merge(additional_params))
66
+ }
67
+ link_to('Download Excel', '#', class: 'btn btn-primary', data: data)
68
+ end
18
69
  end
19
70
  end
@@ -1,13 +1,18 @@
1
1
  module ReportsKit
2
2
  class ModelConfiguration
3
- attr_accessor :dimensions, :filters, :autocomplete_scopes
3
+ attr_accessor :aggregations, :dimensions, :filters, :autocomplete_scopes
4
4
 
5
5
  def initialize
6
+ self.aggregations = []
6
7
  self.dimensions = []
7
8
  self.filters = []
8
9
  self.autocomplete_scopes = []
9
10
  end
10
11
 
12
+ def aggregation(key, expression, properties={})
13
+ aggregations << { key: key.to_s, expression: expression }.merge(properties).symbolize_keys
14
+ end
15
+
11
16
  def dimension(key, properties)
12
17
  dimensions << { key: key.to_s }.merge(properties).symbolize_keys
13
18
  end
@@ -0,0 +1,33 @@
1
+ module ReportsKit
2
+ class Order
3
+ attr_accessor :relation, :field, :direction
4
+
5
+ VALID_RELATIONS = %w(count dimension1 dimension2)
6
+ VALID_FIELDS = [nil, 'label']
7
+ VALID_DIRECTIONS = %w(asc desc)
8
+
9
+ def initialize(relation, field, direction)
10
+ self.relation = relation
11
+ self.field = field
12
+ self.direction = direction
13
+ end
14
+
15
+ def self.parse(string)
16
+ string ||= ''
17
+ field_expression, direction = string.to_s.split(/\s+/)
18
+ relation, field = (field_expression || '').split('.')
19
+
20
+ relation = relation.presence
21
+ field = field.presence
22
+ direction = direction.presence || 'asc'
23
+
24
+ relation = relation.to_i if relation =~ /^\d+$/
25
+
26
+ raise ArgumentError.new("Invalid relation: #{relation}") unless VALID_RELATIONS.include?(relation) || relation.is_a?(Fixnum)
27
+ raise ArgumentError.new("Invalid field: #{field}") unless VALID_FIELDS.include?(field)
28
+ raise ArgumentError.new("Invalid direction: #{direction}") unless VALID_DIRECTIONS.include?(direction)
29
+
30
+ new(relation, field, direction)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,42 @@
1
+ module ReportsKit
2
+ class RelativeTime
3
+ LETTERS_DURATION_METHODS = {
4
+ 'y' => :years,
5
+ 'M' => :months,
6
+ 'w' => :weeks,
7
+ 'd' => :days,
8
+ 'h' => :hours,
9
+ 'm' => :minutes,
10
+ 's' => :seconds
11
+ }
12
+ LETTERS = LETTERS_DURATION_METHODS.keys.join
13
+
14
+ def self.parse(string, prevent_exceptions: false)
15
+ return Time.zone.now if string == 'now'
16
+ original_string = string
17
+ string = string.to_s.strip
18
+ is_negative = string[0, 1] == '-'
19
+ string = string[1..-1] if is_negative
20
+
21
+ result_string = is_negative ? '-' : ''
22
+ result_durations = []
23
+
24
+ string.scan(/(\d+)([#{LETTERS}]?)/) do |number, letter|
25
+ result_string += "#{number}#{letter}"
26
+ duration_method = LETTERS_DURATION_METHODS[letter]
27
+ unless duration_method
28
+ return if prevent_exceptions
29
+ raise ArgumentError.new("Invalid duration letter: #{letter.inspect}")
30
+ end
31
+ result_durations << number.to_i.public_send(duration_method)
32
+ end
33
+
34
+ if result_string == '-' || result_string != original_string.to_s.strip
35
+ return if prevent_exceptions
36
+ raise ArgumentError.new("Invalid time duration: #{original_string.inspect}")
37
+ end
38
+ duration = result_durations.reduce(&:+)
39
+ is_negative ? duration.ago : duration.from_now
40
+ end
41
+ end
42
+ end
@@ -2,15 +2,18 @@ module ReportsKit
2
2
  class ReportBuilder
3
3
  include ActionView::Helpers
4
4
 
5
- attr_accessor :properties
5
+ DEFAULT_DATE_RANGE_VALUE = ['-2M', 'now']
6
6
 
7
- def initialize(properties)
8
- self.properties = normalize_properties(properties)
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
9
12
  end
10
13
 
11
14
  def check_box(filter_key, options={})
12
15
  filter = validate_filter!(filter_key)
13
- checked = filter.properties[:criteria][:operator] == 'true'
16
+ checked = filter.normalized_properties[:criteria][:value] == 'true'
14
17
  check_box_tag(filter_key, '1', checked, options)
15
18
  end
16
19
 
@@ -18,13 +21,17 @@ module ReportsKit
18
21
  filter = validate_filter!(filter_key)
19
22
  defaults = { class: 'form-control input-sm date_range_picker' }
20
23
  options = defaults.deep_merge(options)
21
- text_field_tag(filter_key, filter.properties[:criteria][:value], options)
24
+ value = filter.normalized_properties[:criteria][:value].presence
25
+ value ||= default_date_range_value
26
+ text_field_tag(filter_key, value, options)
22
27
  end
23
28
 
24
29
  def multi_autocomplete(filter_key, options={})
25
30
  validate_filter!(filter_key)
31
+ filter = measure_filters.find { |f| f.key == filter_key.to_s }
26
32
  reports_kit_path = Rails.application.routes.url_helpers.reports_kit_path
27
- path = "#{reports_kit_path}reports_kit/resources/measures/#{measure.key}/filters/#{filter_key}/autocomplete"
33
+ path = "#{reports_kit_path}reports_kit/resources/measures/#{filter.measure.key}/filters/#{filter_key}/autocomplete?"
34
+ path += additional_params.to_query if additional_params.present?
28
35
  scope = options.delete(:scope)
29
36
  params = {}
30
37
  params[:scope] = scope if scope.present?
@@ -46,7 +53,7 @@ module ReportsKit
46
53
  filter = validate_filter!(filter_key)
47
54
  defaults = { class: 'form-control input-sm' }
48
55
  options = defaults.deep_merge(options)
49
- text_field_tag(filter_key, filter.properties[:criteria][:value], options)
56
+ text_field_tag(filter_key, filter.normalized_properties[:criteria][:value], options)
50
57
  end
51
58
 
52
59
  private
@@ -59,18 +66,30 @@ module ReportsKit
59
66
  end
60
67
 
61
68
  def filters
62
- measure.filters
69
+ ui_filters + measure_filters
70
+ end
71
+
72
+ def measure_filters
73
+ measures.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
63
81
  end
64
82
 
65
- def measure
66
- Reports::Measure.new(properties[:measure])
83
+ def measures
84
+ Reports::Measure.new_from_properties!(properties, context_record: nil)
67
85
  end
68
86
 
69
- def normalize_properties(properties)
70
- properties = properties.deep_symbolize_keys
71
- measure = Reports::Measure.new(properties[:measure])
72
- properties[:measure] = measure.properties_with_filters
73
- properties
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
74
93
  end
75
94
  end
76
95
  end