reports_kits 0.7.5 → 0.7.7

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 (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