reports_kits 0.7.5 → 0.7.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -0
  3. data/.rubocop.yml +85 -0
  4. data/.travis.yml +21 -0
  5. data/Appraisals +27 -0
  6. data/Gemfile +3 -0
  7. data/MIT-LICENSE +20 -0
  8. data/README.md +35 -0
  9. data/Rakefile +2 -0
  10. data/app/assets/javascripts/reports_kits/application.js +14 -0
  11. data/app/assets/javascripts/reports_kits/lib/_init.js +9 -0
  12. data/app/assets/javascripts/reports_kits/lib/chart.js +73 -0
  13. data/app/assets/javascripts/reports_kits/lib/report.js +135 -0
  14. data/app/assets/javascripts/reports_kits/lib/table.js +87 -0
  15. data/app/assets/javascripts/reports_kits/vendor/chart.js +12269 -0
  16. data/app/assets/javascripts/reports_kits/vendor/daterangepicker.js +1627 -0
  17. data/app/assets/javascripts/reports_kits/vendor/jquery.tablesorter.min.js +4 -0
  18. data/app/assets/javascripts/reports_kits/vendor/moment.js +4040 -0
  19. data/app/assets/javascripts/reports_kits/vendor/select2.full.js +6436 -0
  20. data/app/assets/stylesheets/reports_kits/application.css.scss +3 -0
  21. data/app/assets/stylesheets/reports_kits/reports.css.sass +33 -0
  22. data/app/assets/stylesheets/reports_kits/select2_overrides.css.sass +7 -0
  23. data/app/assets/stylesheets/reports_kits/vendor/daterangepicker.css +269 -0
  24. data/app/assets/stylesheets/reports_kits/vendor/select2-bootstrap.css +721 -0
  25. data/app/assets/stylesheets/reports_kits/vendor/select2.css +484 -0
  26. data/config/initializers/mime_types.rb +1 -0
  27. data/config/routes.rb +10 -0
  28. data/docs/images/demo.gif +0 -0
  29. data/docs/images/users_by_created_at.png +0 -0
  30. data/gemfiles/mysql.gemfile +7 -0
  31. data/gemfiles/mysql.gemfile.lock +167 -0
  32. data/gemfiles/postgresql.gemfile +7 -0
  33. data/gemfiles/postgresql.gemfile.lock +165 -0
  34. data/gemfiles/postgresql_rails_5.1.4.gemfile +8 -0
  35. data/gemfiles/postgresql_rails_5.1.4.gemfile.lock +168 -0
  36. data/gemfiles/rails_4_mysql.gemfile +8 -0
  37. data/gemfiles/rails_4_mysql.gemfile.lock +165 -0
  38. data/gemfiles/rails_4_postgresql.gemfile +8 -0
  39. data/gemfiles/rails_4_postgresql.gemfile.lock +163 -0
  40. data/gemfiles/rails_5.1.4_postgresql.gemfile +8 -0
  41. data/gemfiles/rails_5.1.4_postgresql.gemfile.lock +169 -0
  42. data/gemfiles/rails_5_mysql.gemfile +8 -0
  43. data/gemfiles/rails_5_mysql.gemfile.lock +171 -0
  44. data/gemfiles/rails_5_postgresql.gemfile +8 -0
  45. data/gemfiles/rails_5_postgresql.gemfile.lock +169 -0
  46. data/lib/reports_kits/base_controller.rb +17 -0
  47. data/lib/reports_kits/cache.rb +37 -0
  48. data/lib/reports_kits/configuration.rb +50 -0
  49. data/lib/reports_kits/engine.rb +21 -0
  50. data/lib/reports_kits/entity.rb +3 -0
  51. data/lib/reports_kits/filters_controller.rb +11 -0
  52. data/lib/reports_kits/form_builder.rb +66 -0
  53. data/lib/reports_kits/helper.rb +24 -0
  54. data/lib/reports_kits/model.rb +16 -0
  55. data/lib/reports_kits/model_configuration.rb +28 -0
  56. data/lib/reports_kits/normalized_params.rb +16 -0
  57. data/lib/reports_kits/order.rb +33 -0
  58. data/lib/reports_kits/relative_time.rb +42 -0
  59. data/lib/reports_kits/report_builder.rb +88 -0
  60. data/lib/reports_kits/reports/abstract_series.rb +9 -0
  61. data/lib/reports_kits/reports/adapters/mysql.rb +26 -0
  62. data/lib/reports_kits/reports/adapters/postgresql.rb +26 -0
  63. data/lib/reports_kits/reports/composite_series.rb +48 -0
  64. data/lib/reports_kits/reports/contextual_filter.rb +19 -0
  65. data/lib/reports_kits/reports/data/add_table_aggregations.rb +105 -0
  66. data/lib/reports_kits/reports/data/aggregate_composite.rb +97 -0
  67. data/lib/reports_kits/reports/data/aggregate_one_dimension.rb +39 -0
  68. data/lib/reports_kits/reports/data/aggregate_two_dimensions.rb +39 -0
  69. data/lib/reports_kits/reports/data/chart_data_for_data_method.rb +62 -0
  70. data/lib/reports_kits/reports/data/chart_options.rb +155 -0
  71. data/lib/reports_kits/reports/data/format_one_dimension.rb +140 -0
  72. data/lib/reports_kits/reports/data/format_table.rb +63 -0
  73. data/lib/reports_kits/reports/data/format_two_dimensions.rb +143 -0
  74. data/lib/reports_kits/reports/data/generate.rb +156 -0
  75. data/lib/reports_kits/reports/data/generate_for_properties.rb +97 -0
  76. data/lib/reports_kits/reports/data/normalize_properties.rb +62 -0
  77. data/lib/reports_kits/reports/data/populate_one_dimension.rb +54 -0
  78. data/lib/reports_kits/reports/data/populate_two_dimensions.rb +104 -0
  79. data/lib/reports_kits/reports/data/utils.rb +178 -0
  80. data/lib/reports_kits/reports/dimension.rb +27 -0
  81. data/lib/reports_kits/reports/dimension_with_series.rb +144 -0
  82. data/lib/reports_kits/reports/filter.rb +29 -0
  83. data/lib/reports_kits/reports/filter_types/base.rb +48 -0
  84. data/lib/reports_kits/reports/filter_types/boolean.rb +47 -0
  85. data/lib/reports_kits/reports/filter_types/datetime.rb +51 -0
  86. data/lib/reports_kits/reports/filter_types/number.rb +30 -0
  87. data/lib/reports_kits/reports/filter_types/records.rb +26 -0
  88. data/lib/reports_kits/reports/filter_types/string.rb +38 -0
  89. data/lib/reports_kits/reports/filter_with_series.rb +97 -0
  90. data/lib/reports_kits/reports/generate_autocomplete_method_results.rb +29 -0
  91. data/lib/reports_kits/reports/generate_autocomplete_results.rb +57 -0
  92. data/lib/reports_kits/reports/inferrable_configuration.rb +116 -0
  93. data/lib/reports_kits/reports/model_settings.rb +30 -0
  94. data/lib/reports_kits/reports/properties.rb +10 -0
  95. data/lib/reports_kits/reports/properties_to_filter.rb +40 -0
  96. data/lib/reports_kits/reports/series.rb +121 -0
  97. data/lib/reports_kits/reports_controller.rb +65 -0
  98. data/lib/reports_kits/utils.rb +11 -0
  99. data/lib/reports_kits/value.rb +3 -0
  100. data/lib/reports_kits/version.rb +3 -0
  101. data/lib/reports_kits.rb +79 -0
  102. data/reports_kits.gemspec +26 -0
  103. data/spec/factories/issue_factory.rb +4 -0
  104. data/spec/factories/issues_label_factory.rb +4 -0
  105. data/spec/factories/label_factory.rb +4 -0
  106. data/spec/factories/pro_repo_factory.rb +5 -0
  107. data/spec/factories/repo_factory.rb +5 -0
  108. data/spec/factories/tag_factory.rb +4 -0
  109. data/spec/fixtures/generate_inputs.yml +254 -0
  110. data/spec/fixtures/generate_outputs.yml +1216 -0
  111. data/spec/reports_kit/form_builder_spec.rb +26 -0
  112. data/spec/reports_kit/relative_time_spec.rb +29 -0
  113. data/spec/reports_kit/reports/data/generate/contextual_filters_spec.rb +60 -0
  114. data/spec/reports_kit/reports/data/generate_spec.rb +1371 -0
  115. data/spec/reports_kit/reports/data/normalize_properties_spec.rb +196 -0
  116. data/spec/reports_kit/reports/dimension_with_series_spec.rb +67 -0
  117. data/spec/reports_kit/reports/filter_with_series_spec.rb +39 -0
  118. data/spec/reports_kit/reports/generate_autocomplete_results_spec.rb +69 -0
  119. data/spec/spec_helper.rb +77 -0
  120. data/spec/support/config.rb +41 -0
  121. data/spec/support/example_data_methods.rb +25 -0
  122. data/spec/support/factory_girl.rb +5 -0
  123. data/spec/support/helpers.rb +25 -0
  124. data/spec/support/models/issue.rb +14 -0
  125. data/spec/support/models/issues_label.rb +4 -0
  126. data/spec/support/models/label.rb +5 -0
  127. data/spec/support/models/pro/repo.rb +5 -0
  128. data/spec/support/models/pro/special_issue.rb +4 -0
  129. data/spec/support/models/repo.rb +13 -0
  130. data/spec/support/models/tag.rb +4 -0
  131. data/spec/support/schema.rb +39 -0
  132. metadata +134 -4
@@ -0,0 +1,196 @@
1
+ require 'spec_helper'
2
+
3
+ describe ReportsKit::Reports::Data::NormalizeProperties do
4
+ describe '#perform' do
5
+ let(:normalized_properties) { described_class.new(properties).perform }
6
+ let(:series) { normalized_properties[:series] }
7
+ let(:context_params) { { foo: 'bar' } }
8
+ let(:name) { 'Foo' }
9
+
10
+ context 'without a series key' do
11
+ let(:properties) do
12
+ {
13
+ measure: 'issue',
14
+ dimensions: %w(opened_at)
15
+ }
16
+ end
17
+
18
+ it 'normalizes' do
19
+ expect(series).to eq([properties])
20
+ end
21
+ end
22
+
23
+ context 'with a series key' do
24
+ let(:properties) do
25
+ {
26
+ series: {
27
+ measure: 'issue',
28
+ dimensions: %w(opened_at)
29
+ }
30
+ }
31
+ end
32
+
33
+ it 'normalizes' do
34
+ expect(series).to eq([properties[:series]])
35
+ end
36
+ end
37
+
38
+ context 'with a series array and context_params' do
39
+ let(:properties) do
40
+ {
41
+ series: [{
42
+ measure: 'issue',
43
+ dimensions: %w(opened_at)
44
+ }],
45
+ context_params: context_params
46
+ }
47
+ end
48
+
49
+ it 'normalizes' do
50
+ expect(series).to eq([{
51
+ measure: 'issue',
52
+ dimensions: %w(opened_at),
53
+ context_params: context_params
54
+ }])
55
+ end
56
+ end
57
+
58
+ context 'with a composite series and context_params' do
59
+ let(:properties) do
60
+ {
61
+ name: name,
62
+ composite_operator: '%',
63
+ series: [
64
+ {
65
+ measure: 'issue',
66
+ dimensions: %w(created_at)
67
+ },
68
+ {
69
+ measure: 'tag',
70
+ dimensions: %w(created_at)
71
+ }
72
+ ],
73
+ context_params: context_params
74
+ }
75
+ end
76
+
77
+ it 'copies the context_params to the series' do
78
+ expect(normalized_properties).to eq({
79
+ name: name,
80
+ composite_operator: '%',
81
+ series: [
82
+ {
83
+ measure: 'issue',
84
+ dimensions: %w(created_at),
85
+ context_params: context_params
86
+ },
87
+ {
88
+ measure: 'tag',
89
+ dimensions: %w(created_at),
90
+ context_params: context_params
91
+ }
92
+ ],
93
+ context_params: context_params
94
+ })
95
+ end
96
+ end
97
+
98
+ context 'with a composite series and context_params' do
99
+ let(:properties) do
100
+ {
101
+ series: [
102
+ {
103
+ name: name,
104
+ composite_operator: '+',
105
+ series: [
106
+ {
107
+ measure: 'issue',
108
+ dimensions: %w(created_at)
109
+ }
110
+ ]
111
+ }
112
+ ],
113
+ context_params: context_params
114
+ }
115
+ end
116
+
117
+ it 'copies the context_params to the series' do
118
+ expect(normalized_properties).to eq({
119
+ series: [
120
+ {
121
+ name: name,
122
+ composite_operator: '+',
123
+ series: [
124
+ {
125
+ measure: 'issue',
126
+ dimensions: %w(created_at),
127
+ context_params: context_params
128
+ }
129
+ ],
130
+ context_params: context_params
131
+ }
132
+ ],
133
+ context_params: context_params
134
+ })
135
+ end
136
+ end
137
+
138
+ context 'with a composite series, a series, and context_params' do
139
+ let(:properties) do
140
+ {
141
+ series: [
142
+ {
143
+ measure: 'issue',
144
+ dimensions: %w(opened_at)
145
+ },
146
+ {
147
+ name: name,
148
+ composite_operator: '%',
149
+ series: [
150
+ {
151
+ measure: 'issue',
152
+ dimensions: %w(created_at)
153
+ },
154
+ {
155
+ measure: 'tag',
156
+ dimensions: %w(created_at)
157
+ }
158
+ ]
159
+ }
160
+ ],
161
+ context_params: context_params
162
+ }
163
+ end
164
+
165
+ it 'copies the context_params to the series' do
166
+ expect(normalized_properties).to eq({
167
+ series: [
168
+ {
169
+ measure: 'issue',
170
+ dimensions: %w(opened_at),
171
+ context_params: context_params
172
+ },
173
+ {
174
+ name: name,
175
+ composite_operator: '%',
176
+ series: [
177
+ {
178
+ measure: 'issue',
179
+ dimensions: %w(created_at),
180
+ context_params: context_params
181
+ },
182
+ {
183
+ measure: 'tag',
184
+ dimensions: %w(created_at),
185
+ context_params: context_params
186
+ }
187
+ ],
188
+ context_params: context_params
189
+ }
190
+ ],
191
+ context_params: context_params
192
+ })
193
+ end
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe ReportsKit::Reports::DimensionWithSeries do
4
+ subject { described_class.new(dimension: dimension, series: series) }
5
+ let(:dimension) { ReportsKit::Reports::Dimension.new(properties) }
6
+ let(:series) { ReportsKit::Reports::Series.new(measure: 'issue', dimensions: [properties]) }
7
+
8
+ describe 'settings' do
9
+ context 'with a datetime dimension' do
10
+ let(:properties) { 'opened_at' }
11
+
12
+ it 'returns the settings' do
13
+ expect(subject.settings).to eq({ column: 'issues.opened_at', group: database_adapter.truncate_to_week('issues.opened_at') })
14
+ end
15
+ end
16
+
17
+ context 'with a string dimension' do
18
+ let(:properties) { 'title' }
19
+
20
+ it 'returns the settings' do
21
+ expect(subject.settings).to eq({ column: 'issues.title', group: 'issues.title' })
22
+ end
23
+ end
24
+
25
+ context 'with a text dimension' do
26
+ let(:properties) { 'description' }
27
+
28
+ it 'returns the settings' do
29
+ expect(subject.settings).to eq({ column: 'issues.description', group: 'issues.description' })
30
+ end
31
+ end
32
+
33
+ context 'with a belongs_to association dimension' do
34
+ let(:properties) { 'repo' }
35
+
36
+ it 'returns the settings' do
37
+ expect(subject.settings).to eq({ column: 'issues.repo_id', group: 'issues.repo_id' })
38
+ end
39
+ end
40
+
41
+ context 'with a has_many association dimension' do
42
+ let(:properties) { 'tags' }
43
+
44
+ it 'returns the settings' do
45
+ expect(subject.settings).to eq({ joins: :tags, column: 'tags.id', group: 'issues.issue_id' })
46
+ end
47
+ end
48
+
49
+ context 'with a has_many :through association dimension' do
50
+ let(:properties) { 'labels' }
51
+
52
+ it 'returns the settings' do
53
+ expect(subject.settings).to eq({ joins: :issues_labels, column: 'issues_labels.label_id', group: 'issues_labels.label_id' })
54
+ end
55
+ end
56
+
57
+ describe ':key_to_label setting' do
58
+ context 'with a Proc' do
59
+ let(:properties) { 'titleized_state' }
60
+
61
+ it 'returns the result of the Proc' do
62
+ expect(subject.key_to_label('foo')).to eq('Foo')
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe ReportsKit::Reports::FilterWithSeries do
4
+ subject { described_class.new(filter: filter, series: series) }
5
+ let(:filter) { ReportsKit::Reports::Filter.new(properties) }
6
+ let(:series) { ReportsKit::Reports::Series.new(measure: 'issue', dimensions: %w(repo)) }
7
+
8
+ context 'with a datetime filter' do
9
+ let(:properties) { 'opened_at' }
10
+
11
+ it 'returns the settings' do
12
+ expect(subject.settings).to eq({ column: 'issues.opened_at' })
13
+ end
14
+ end
15
+
16
+ context 'with a belongs_to association filter' do
17
+ let(:properties) { 'repo' }
18
+
19
+ it 'returns the settings' do
20
+ expect(subject.settings).to eq({ column: 'issues.repo_id' })
21
+ end
22
+ end
23
+
24
+ context 'with a has_many association filter' do
25
+ let(:properties) { 'tags' }
26
+
27
+ it 'returns the settings' do
28
+ expect(subject.settings).to eq({ joins: :tags, column: 'tags.id' })
29
+ end
30
+ end
31
+
32
+ context 'with a has_many :through association filter' do
33
+ let(:properties) { 'labels' }
34
+
35
+ it 'returns the settings' do
36
+ expect(subject.settings).to eq({ joins: :issues_labels, column: 'issues_labels.label_id' })
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,69 @@
1
+ require 'spec_helper'
2
+
3
+ describe ReportsKit::Reports::GenerateAutocompleteResults do
4
+ subject { described_class.new(params, properties).perform }
5
+ let!(:repo) { create(:repo) }
6
+ let!(:repo2) { create(:repo) }
7
+ let!(:issues) do
8
+ [
9
+ create(:issue, repo: repo, opened_at: now - 2.weeks),
10
+ create(:issue, repo: repo2, opened_at: now - 2.weeks),
11
+ create(:issue, repo: repo, opened_at: now)
12
+ ]
13
+ end
14
+
15
+ context 'with valid params' do
16
+ let(:params) { { key: 'repo' } }
17
+ let(:properties) do
18
+ {
19
+ measure: 'issue',
20
+ filters: %w(repo),
21
+ dimensions: %w(opened_at)
22
+ }
23
+ end
24
+
25
+ it 'returns the results' do
26
+ expect(subject).to match_array([
27
+ { id: repo.id, text: repo.to_s },
28
+ { id: repo2.id, text: repo2.to_s }
29
+ ])
30
+ end
31
+ end
32
+
33
+ context 'with a contextual_filter' do
34
+ context 'with context_params' do
35
+ let(:params) { { key: 'repo', context_params: { repo_id: repo.id } } }
36
+ let(:properties) do
37
+ {
38
+ measure: 'issue',
39
+ filters: [{ key: 'repo', contextual_filters: %w(for_repo) }],
40
+ dimensions: %w(opened_at)
41
+ }
42
+ end
43
+
44
+ it 'returns the results' do
45
+ expect(subject).to match_array([
46
+ { id: repo.id, text: repo.to_s }
47
+ ])
48
+ end
49
+ end
50
+
51
+ context 'without context_params' do
52
+ let(:params) { { key: 'repo' } }
53
+ let(:properties) do
54
+ {
55
+ measure: 'issue',
56
+ filters: [{ key: 'repo', contextual_filters: %w(for_repo) }],
57
+ dimensions: %w(opened_at)
58
+ }
59
+ end
60
+
61
+ it 'returns the results' do
62
+ expect(subject).to match_array([
63
+ { id: repo.id, text: repo.to_s },
64
+ { id: repo2.id, text: repo2.to_s }
65
+ ])
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,77 @@
1
+ require 'reports_kit'
2
+
3
+ require 'database_cleaner'
4
+ require 'groupdate'
5
+ require 'pry'
6
+ require 'pry-byebug'
7
+ require 'timecop'
8
+ require 'support/factory_girl'
9
+ require 'support/helpers'
10
+
11
+ Time.zone = ActiveSupport::TimeZone.new('UTC')
12
+ ActiveRecord::Base.default_timezone = :utc
13
+
14
+ if Gem.loaded_specs.key?('mysql2')
15
+ REPORTS_KIT_DATABASE_ADAPTER = ReportsKit::Reports::Adapters::Mysql
16
+ REPORTS_KIT_DATABASE_TYPE = :mysql
17
+ ActiveRecord::Base.establish_connection(
18
+ adapter: 'mysql2',
19
+ host: ENV['MYSQL_HOST'] || 'localhost',
20
+ database: 'reports_kit_test',
21
+ username: 'root'
22
+ )
23
+ else
24
+ REPORTS_KIT_DATABASE_ADAPTER = ReportsKit::Reports::Adapters::Postgresql
25
+ REPORTS_KIT_DATABASE_TYPE = :postgresql
26
+ ActiveRecord::Base.establish_connection(
27
+ adapter: 'postgresql',
28
+ host: ENV['POSTGRESQL_HOST'] || 'localhost',
29
+ database: 'reports_kit_test',
30
+ username: 'postgres'
31
+ )
32
+ end
33
+ directory = File.dirname(File.absolute_path(__FILE__))
34
+ Dir.glob("#{directory}/support/models/*.rb") { |file| require file }
35
+ Dir.glob("#{directory}/support/models/**/*.rb") { |file| require file }
36
+ Dir.glob("#{directory}/factories/*.rb") { |file| require file }
37
+
38
+ require 'support/config'
39
+ require 'support/example_data_methods'
40
+ require 'support/schema'
41
+
42
+ RSpec.configure do |config|
43
+ # ## Mock Framework
44
+ #
45
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
46
+ #
47
+ # config.mock_with :mocha
48
+ # config.mock_with :flexmock
49
+ # config.mock_with :rr
50
+
51
+ # Run specs in random order to surface order dependencies. If you find an
52
+ # order dependency and want to debug it, you can fix the order by providing
53
+ # the seed, which is printed after each run.
54
+ # --seed 1234
55
+ config.order = 'random'
56
+
57
+ TIMECOP_TIME = Time.utc(2010)
58
+ config.before(:each) do
59
+ Timecop.freeze(TIMECOP_TIME)
60
+ end
61
+ config.after(:each) do
62
+ Timecop.return
63
+ end
64
+
65
+ config.before(:suite) do
66
+ # To support multi-threaded ActiveRecord queries, we need to use :truncation instead of :transaction.
67
+ DatabaseCleaner.strategy = [:truncation, pre_count: true]
68
+ end
69
+
70
+ config.around(:each) do |example|
71
+ DatabaseCleaner.cleaning do
72
+ example.run
73
+ end
74
+ end
75
+
76
+ config.include Helpers
77
+ end
@@ -0,0 +1,41 @@
1
+ ReportsKit.configure do |config|
2
+ config.custom_methods = {
3
+ format_percentage: -> (value) { "#{value.round(0)}%" },
4
+ add_label_link: -> (data:, properties:, context_record:) {
5
+ data[:entities].each do |entity|
6
+ entity.label = "<a href='#'>#{entity.label}</a> Bar" if entity.label
7
+ end
8
+ data
9
+ },
10
+ add_label_suffix: -> (data:, properties:, context_record:) {
11
+ data[:entities].each do |entity|
12
+ entity.label = "#{entity.label} Foo" if entity.label
13
+ end
14
+ data
15
+ },
16
+ add_context_record_suffix: -> (data:, properties:, context_record:) {
17
+ data[:entities].each do |entity|
18
+ entity.label = "#{entity.label} #{context_record}" if entity.label
19
+ end
20
+ data
21
+ },
22
+ empty_result_set_for_relation: -> (relation) {
23
+ relation.where('0 = 1')
24
+ },
25
+ prepend_column: -> (data:, properties:, context_record:) {
26
+ values = data[:entities].map do |entity|
27
+ value = entity.instance.is_a?(Date) ? entity.instance.mday : nil
28
+ ReportsKit::Value.new(value, value)
29
+ end
30
+ new_dataset = {
31
+ entity: ReportsKit::Entity.new('day_of_month', 'Day of Month', 'day_of_month'),
32
+ values: values
33
+ }
34
+ data[:datasets] = [new_dataset] + data[:datasets]
35
+ data
36
+ },
37
+ all_repo_ids: -> (dimension_keys:, properties:, context_record:) {
38
+ Repo.pluck(:id)
39
+ }
40
+ }
41
+ end
@@ -0,0 +1,25 @@
1
+ class ExampleDataMethods
2
+ def self.issues_by_opened_at(properties)
3
+ Issue.group_by_week(:opened_at).count.map { |date, count| [format_date(date), count] }
4
+ end
5
+
6
+ def self.issues_by_opened_at_and_repo(properties)
7
+ Issue.group_by_week(:opened_at).joins(:repo).group('repos.full_name').count.map do |(date, name), count|
8
+ [[format_date(date), name], count]
9
+ end
10
+ end
11
+
12
+ def self.issues_by_opened_at_with_filters(properties)
13
+ format = properties[:format]
14
+ ui_filters = properties[:ui_filters]
15
+ issues = Issue.group_by_week(:opened_at)
16
+ issues = issues.where(state: ui_filters[:state]) if ui_filters.try(:[], :state).present?
17
+ dates_issue_counts = issues.count.map { |date, count| [format_date(date), count] }
18
+ return dates_issue_counts unless format == 'table'
19
+ [['Date', 'Issue count']] + dates_issue_counts
20
+ end
21
+
22
+ def self.format_date(date)
23
+ date.strftime('%b %-d, \'%y')
24
+ end
25
+ end
@@ -0,0 +1,5 @@
1
+ require 'factory_girl'
2
+
3
+ RSpec.configure do |config|
4
+ config.include FactoryGirl::Syntax::Methods
5
+ end
@@ -0,0 +1,25 @@
1
+ module Helpers
2
+ def now
3
+ Time.zone.now
4
+ end
5
+
6
+ def database_adapter
7
+ REPORTS_KIT_DATABASE_ADAPTER
8
+ end
9
+
10
+ def format_configuration_time(time)
11
+ ReportsKit::Reports::Data::Utils.format_configuration_time(time)
12
+ end
13
+
14
+ def format_csv_week_offset(week_offset)
15
+ ReportsKit::Reports::Data::Utils.format_csv_time((now - week_offset.weeks).beginning_of_week(ReportsKit.configuration.first_day_of_week))
16
+ end
17
+
18
+ def format_day_offset(day_offset)
19
+ ReportsKit::Reports::Data::Utils.format_display_time((now - day_offset.days))
20
+ end
21
+
22
+ def format_week_offset(week_offset)
23
+ ReportsKit::Reports::Data::Utils.format_display_time((now - week_offset.weeks).beginning_of_week(ReportsKit.configuration.first_day_of_week))
24
+ end
25
+ end
@@ -0,0 +1,14 @@
1
+ class Issue < ActiveRecord::Base
2
+ include ReportsKit::Model
3
+
4
+ belongs_to :repo
5
+ has_many :issues_labels
6
+ has_many :labels, through: :issues_labels
7
+ has_many :tags
8
+
9
+ reports_kit do
10
+ aggregation :average_duration, [:average, REPORTS_KIT_DATABASE_TYPE == :mysql ? 'DATEDIFF(closed_at, opened_at)' : '(closed_at::date - opened_at::date)']
11
+ contextual_filter :for_repo, ->(relation, context_params) { context_params ? relation.where(repo_id: context_params[:repo_id]) : relation }
12
+ dimension :titleized_state, group: 'issues.state', key_to_label: -> (state) { state.try(:titleize) }
13
+ end
14
+ end
@@ -0,0 +1,4 @@
1
+ class IssuesLabel < ActiveRecord::Base
2
+ belongs_to :issue
3
+ belongs_to :label
4
+ end
@@ -0,0 +1,5 @@
1
+ class Label < ActiveRecord::Base
2
+ belongs_to :repo
3
+ has_many :issues_labels
4
+ has_many :issues, through: :issues_labels
5
+ end
@@ -0,0 +1,5 @@
1
+ module Pro
2
+ class Repo < ::Repo
3
+ has_many :special_issues
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ module Pro
2
+ class SpecialIssue < ::Issue
3
+ end
4
+ end
@@ -0,0 +1,13 @@
1
+ class Repo < ActiveRecord::Base
2
+ include ReportsKit::Model
3
+
4
+ has_many :issues
5
+
6
+ reports_kit do
7
+ contextual_filter :for_repo, ->(relation, context_params) { context_params ? relation.where(id: context_params[:repo_id]) : relation }
8
+ end
9
+
10
+ def to_s
11
+ full_name
12
+ end
13
+ end
@@ -0,0 +1,4 @@
1
+ class Tag < ActiveRecord::Base
2
+ belongs_to :repo
3
+ belongs_to :issue
4
+ end
@@ -0,0 +1,39 @@
1
+ ActiveRecord::Schema.define do
2
+ self.verbose = false
3
+
4
+ create_table :issues, :force => :cascade do |t|
5
+ t.integer :repo_id
6
+ t.string :title
7
+ t.text :description
8
+ t.integer :source_user_id
9
+ t.string :state
10
+ t.boolean :locked
11
+ t.datetime :opened_at
12
+ t.datetime :closed_at
13
+ t.timestamps
14
+ end
15
+
16
+ create_table :issues_labels, force: :cascade do |t|
17
+ t.integer :issue_id
18
+ t.integer :label_id
19
+ t.timestamps
20
+ end
21
+
22
+ create_table :labels, force: :cascade do |t|
23
+ t.integer :repo_id
24
+ t.string :name
25
+ t.timestamps
26
+ end
27
+
28
+ create_table :repos, :force => :cascade do |t|
29
+ t.string :full_name
30
+ t.timestamps
31
+ end
32
+
33
+ create_table :tags, force: :cascade do |t|
34
+ t.integer :repo_id
35
+ t.integer :issue_id
36
+ t.string :name
37
+ t.timestamps
38
+ end
39
+ end