effective_reports 0.1.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 (33) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +110 -0
  4. data/Rakefile +18 -0
  5. data/app/assets/config/effective_reports_manifest.js +3 -0
  6. data/app/assets/javascripts/effective_reports/base.js +15 -0
  7. data/app/assets/javascripts/effective_reports.js +1 -0
  8. data/app/assets/stylesheets/effective_reports/base.scss +0 -0
  9. data/app/assets/stylesheets/effective_reports.scss +1 -0
  10. data/app/controllers/admin/reports_controller.rb +16 -0
  11. data/app/datatables/admin/effective_reports_datatable.rb +31 -0
  12. data/app/datatables/effective_report_datatable.rb +21 -0
  13. data/app/helpers/effective_reports_helper.rb +60 -0
  14. data/app/mailers/effective/reports_mailer.rb +38 -0
  15. data/app/models/concerns/acts_as_reportable.rb +72 -0
  16. data/app/models/effective/report.rb +94 -0
  17. data/app/models/effective/report_column.rb +89 -0
  18. data/app/models/effective/report_scope.rb +48 -0
  19. data/app/views/admin/reports/_form.html.haml +8 -0
  20. data/app/views/admin/reports/_form_report.html.haml +194 -0
  21. data/app/views/admin/reports/_layout.html.haml +2 -0
  22. data/app/views/admin/reports/_report.html.haml +17 -0
  23. data/config/effective_reports.rb +37 -0
  24. data/config/routes.rb +16 -0
  25. data/db/migrate/01_create_effective_reports.rb.erb +54 -0
  26. data/db/seeds.rb +1 -0
  27. data/lib/effective_reports/engine.rb +18 -0
  28. data/lib/effective_reports/version.rb +3 -0
  29. data/lib/effective_reports.rb +27 -0
  30. data/lib/generators/effective_reports/install_generator.rb +32 -0
  31. data/lib/generators/templates/effective_reports_mailer_preview.rb +4 -0
  32. data/lib/tasks/effective_reports_tasks.rake +8 -0
  33. metadata +270 -0
@@ -0,0 +1,194 @@
1
+ = effective_form_with(model: [:admin, report], engine: true) do |f|
2
+ = f.text_field :title
3
+ = f.text_area :description
4
+
5
+ - if f.object.new_record?
6
+ = f.select :reportable_class_name, EffectiveReports.reportable_classes.map(&:name), label: 'Resource',
7
+ 'data-load-ajax-url': effective_reports.new_admin_report_path,
8
+ 'data-load-ajax-div': '#effective-reports-ajax'
9
+ - else
10
+ = f.static_field :reportable_class_name, label: 'Resource'
11
+
12
+ #effective-reports-ajax
13
+ -# Attributes
14
+ - attributes = f.object.reportable_attributes
15
+ - attributes_collection = reportable_attributes_collection(attributes)
16
+
17
+ - value_booleans = attributes.select { |_, type| type == :boolean }.keys
18
+ - value_dates = attributes.select { |_, type| type == :date }.keys
19
+ - value_decimals = attributes.select { |_, type| type == :decimal }.keys
20
+ - value_integers = attributes.select { |_, type| type == :integer }.keys
21
+ - value_prices = attributes.select { |_, type| type == :price }.keys
22
+ - value_strings = attributes.select { |_, type| type == :string }.keys
23
+
24
+ - value_belong_tos = attributes.select { |_, type| type == :belongs_to }.keys
25
+ - value_belong_to_polymorphics = attributes.select { |_, type| type == :belongs_to_polymorphic }.keys
26
+ - value_has_manys = attributes.select { |_, type| type == :has_many }.keys
27
+ - value_has_ones = attributes.select { |_, type| type == :has_one }.keys
28
+
29
+ -# Scopes
30
+ - scopes = f.object.reportable_scopes
31
+ - scopes_collection = reportable_scopes_collection(scopes)
32
+
33
+ - if attributes.present?
34
+ %h2 Report Columns
35
+
36
+ = f.has_many :report_columns do |frc|
37
+ .card.mb-2
38
+ .card-body.pb-2
39
+ .row
40
+ .col-md-4
41
+ = frc.select :name, attributes_collection, grouped: true, required: false, label: false
42
+ .col
43
+ = frc.show_if_any(:name, value_booleans) do
44
+
45
+ .row
46
+ .col.mt-2
47
+ = frc.check_box :filter, label: 'Filter by this column'
48
+ = frc.hidden_field :as, value: :boolean
49
+
50
+ .col.effective-report-filter{style: ('display: none;' unless frc.object.filter?)}
51
+ = frc.select :operation, reportable_operations_collection(:boolean), label: false
52
+
53
+ .col.effective-report-filter{style: ('display: none;' unless frc.object.filter?)}
54
+ = frc.radios :value_boolean, reportable_boolean_collection, label: false, buttons: true
55
+
56
+ = frc.show_if_any(:name, value_dates) do
57
+ .row
58
+ .col.mt-2
59
+ = frc.check_box :filter, label: 'Filter by this column'
60
+ = frc.hidden_field :as, value: :date
61
+
62
+ .col.effective-report-filter{style: ('display: none;' unless frc.object.filter?)}
63
+ = frc.select :operation, reportable_operations_collection(:date), label: false
64
+
65
+ .col.effective-report-filter{style: ('display: none;' unless frc.object.filter?)}
66
+ = frc.date_field :value_date, label: false
67
+
68
+ = frc.show_if_any(:name, value_decimals) do
69
+ .row
70
+ .col.mt-2
71
+ = frc.check_box :filter, label: 'Filter by this column'
72
+ = frc.hidden_field :as, value: :decimal
73
+
74
+ .col.effective-report-filter{style: ('display: none;' unless frc.object.filter?)}
75
+ = frc.select :operation, reportable_operations_collection(:decimal), label: false
76
+
77
+ .col.effective-report-filter{style: ('display: none;' unless frc.object.filter?)}
78
+ = frc.float_field :value_decimal, label: false
79
+
80
+ = frc.show_if_any(:name, value_integers) do
81
+ .row
82
+ .col.mt-2
83
+ = frc.check_box :filter, label: 'Filter by this column'
84
+ = frc.hidden_field :as, value: :integer
85
+
86
+ .col.effective-report-filter{style: ('display: none;' unless frc.object.filter?)}
87
+ = frc.select :operation, reportable_operations_collection(:integer), label: false
88
+
89
+ .col.effective-report-filter{style: ('display: none;' unless frc.object.filter?)}
90
+ = frc.integer_field :value_integer, label: false
91
+
92
+ = frc.show_if_any(:name, value_prices) do
93
+ .row
94
+ .col.mt-2
95
+ = frc.check_box :filter, label: 'Filter by this column'
96
+ = frc.hidden_field :as, value: :price
97
+
98
+ .col.effective-report-filter{style: ('display: none;' unless frc.object.filter?)}
99
+ = frc.select :operation, reportable_operations_collection(:price), label: false
100
+
101
+ .col.effective-report-filter{style: ('display: none;' unless frc.object.filter?)}
102
+ = frc.price_field :value_price, label: false
103
+
104
+ = frc.show_if_any(:name, value_strings) do
105
+ .row
106
+ .col.mt-2
107
+ = frc.check_box :filter, label: 'Filter by this column'
108
+ = frc.hidden_field :as, value: :string
109
+
110
+ .col.effective-report-filter{style: ('display: none;' unless frc.object.filter?)}
111
+ = frc.select :operation, reportable_operations_collection(:string), label: false
112
+
113
+ .col.effective-report-filter{style: ('display: none;' unless frc.object.filter?)}
114
+ = frc.text_field :value_string, label: false
115
+
116
+ = frc.show_if_any(:name, value_belong_tos) do
117
+ .row
118
+ .col.mt-2
119
+ = frc.check_box :filter, label: 'Filter by this column'
120
+ = frc.hidden_field :as, value: :belongs_to
121
+
122
+ .col.effective-report-filter{style: ('display: none;' unless frc.object.filter?)}
123
+ = frc.select :operation, reportable_operations_collection(:belongs_to), label: false
124
+
125
+ .col.effective-report-filter{style: ('display: none;' unless frc.object.filter?)}
126
+ = frc.text_field :value_associated, label: false
127
+
128
+ = frc.show_if_any(:name, value_belong_to_polymorphics) do
129
+ .row
130
+ .col.mt-2
131
+ = frc.check_box :filter, label: 'Filter by this column'
132
+ = frc.hidden_field :as, value: :belongs_to_polymorphic
133
+
134
+ .col.effective-report-filter{style: ('display: none;' unless frc.object.filter?)}
135
+ = frc.select :operation, reportable_operations_collection(:belongs_to_polymorphic), label: false
136
+
137
+ .col.effective-report-filter{style: ('display: none;' unless frc.object.filter?)}
138
+ = frc.text_field :value_associated, label: false
139
+
140
+
141
+ = frc.show_if_any(:name, value_has_manys) do
142
+ .row
143
+ .col.mt-2
144
+ = frc.check_box :filter, label: 'Filter by this column'
145
+ = frc.hidden_field :as, value: :has_many
146
+
147
+ .col.effective-report-filter{style: ('display: none;' unless frc.object.filter?)}
148
+ = frc.select :operation, reportable_operations_collection(:has_many), label: false
149
+
150
+ .col.effective-report-filter{style: ('display: none;' unless frc.object.filter?)}
151
+ = frc.text_field :value_associated, label: false
152
+
153
+ = frc.show_if_any(:name, value_has_ones) do
154
+ .row
155
+ .col.mt-2
156
+ = frc.check_box :filter, label: 'Filter by this column'
157
+ = frc.hidden_field :as, value: :has_one
158
+
159
+ .col.effective-report-filter{style: ('display: none;' unless frc.object.filter?)}
160
+ = frc.select :operation, reportable_operations_collection(:has_one), label: false
161
+
162
+ .col.effective-report-filter{style: ('display: none;' unless frc.object.filter?)}
163
+ = frc.text_field :value_associated, label: false
164
+
165
+ - if scopes.present?
166
+ %h2 Report Scopes
167
+
168
+ = f.has_many :report_scopes do |frs|
169
+ .card.mb-2
170
+ .card-body.pb-2
171
+ .row
172
+ .col
173
+ = frs.select :name, scopes_collection, grouped: true, required: false, label: false
174
+ .col
175
+ - scopes.select { |scope, type| type.present? }.each do |scope, type|
176
+ = frs.show_if(:name, scope) do
177
+ = frs.hidden_field :advanced, value: true
178
+
179
+ - if type == :boolean
180
+ = frs.radios :value_boolean, reportable_boolean_collection, label: 'Value', buttons: true, required: true, label: false
181
+ - elsif type == :date
182
+ = frs.date_field :value_date, label: 'Value', required: true, label: false
183
+ - elsif type == :decimal
184
+ = frs.date_field :value_decimal, label: 'Value', required: true, label: false
185
+ - elsif type == :integer
186
+ = frs.integer_field :value_integer, label: 'Value', required: true, label: false
187
+ - elsif type == :price
188
+ = frs.price_field :value_price, label: 'Value', required: true, label: false
189
+ - elsif type == :string
190
+ = frs.text_field :value_string, label: 'Value', required: true, label: false
191
+ - else
192
+ - raise("Unexpected scope datatype: #{type || 'nil'}")
193
+
194
+ = effective_submit(f)
@@ -0,0 +1,2 @@
1
+ .effective-reports
2
+ = yield
@@ -0,0 +1,17 @@
1
+ - if report.description.present?
2
+ %p= report.description.to_s
3
+
4
+ - if report.filtered_report_columns.present? || report.report_scopes.present?
5
+ %p The results of this report have been filtered by the following:
6
+
7
+ - if report.filtered_report_columns.present?
8
+ %p= badges(report.filtered_report_columns.map(&:to_s))
9
+
10
+ - if report.report_scopes.present?
11
+ %p= badges(report.report_scopes.map(&:to_s))
12
+
13
+ = collapse('Show SQL') do
14
+ %p= report.collection.to_sql
15
+
16
+ - datatable = EffectiveReportDatatable.new(report: report)
17
+ = render_datatable(datatable)
@@ -0,0 +1,37 @@
1
+ EffectiveReports.setup do |config|
2
+ config.reports_table_name = :reports
3
+ config.report_columns_table_name = :report_columns
4
+ config.report_scopes_table_name = :report_scopes
5
+
6
+ # Layout Settings
7
+ # Configure the Layout per controller, or all at once
8
+ # config.layout = { application: 'application', admin: 'admin' }
9
+
10
+ # Reports Settings
11
+ # Configure the class responsible for the reports.
12
+ # This should extend from Effective::Reports
13
+ # config.reports_class_name = 'Effective::Reports'
14
+
15
+ # Reportable Class Names
16
+ # The following classes will be available to build reports from
17
+ # They must define acts_as_reportable to be included
18
+ config.reportable_class_names = ['User', 'Effective::Order']
19
+
20
+ # Mailer Settings
21
+ # Please see config/initializers/effective_reports.rb for default effective_* gem mailer settings
22
+ #
23
+ # Configure the class responsible to send e-mails.
24
+ # config.mailer = 'Effective::ReportsMailer'
25
+ #
26
+ # Override effective_resource mailer defaults
27
+ #
28
+ # config.parent_mailer = nil # The parent class responsible for sending emails
29
+ # config.deliver_method = nil # The deliver method, deliver_later or deliver_now
30
+ # config.mailer_layout = nil # Default mailer layout
31
+ # config.mailer_sender = nil # Default From value
32
+ # config.mailer_admin = nil # Default To value for Admin correspondence
33
+ # config.mailer_subject = nil # Proc.new method used to customize Subject
34
+
35
+ # Will work with effective_email_templates gem
36
+ config.use_effective_email_templates = true
37
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ Rails.application.routes.draw do
4
+ mount EffectiveReports::Engine => '/', as: 'effective_reports'
5
+ end
6
+
7
+ EffectiveReports::Engine.routes.draw do
8
+ # Public routes
9
+ scope module: 'effective' do
10
+ end
11
+
12
+ namespace :admin do
13
+ resources :reports
14
+ end
15
+
16
+ end
@@ -0,0 +1,54 @@
1
+ class CreateEffectiveReports < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table <%= @reports_table_name %> do |t|
4
+ t.integer :created_by_id
5
+ t.string :created_by_type
6
+
7
+ t.string :title
8
+ t.text :description
9
+
10
+ t.string :reportable_class_name
11
+
12
+ t.timestamps
13
+ end
14
+
15
+ create_table <%= @report_columns_table_name %> do |t|
16
+ t.integer :report_id
17
+
18
+ t.string :name
19
+ t.integer :position
20
+
21
+ t.string :as
22
+
23
+ t.boolean :filter
24
+ t.string :operation
25
+
26
+ t.text :value_associated
27
+ t.boolean :value_boolean
28
+ t.date :value_date
29
+ t.decimal :value_decimal
30
+ t.integer :value_integer
31
+ t.integer :value_price
32
+ t.string :value_string
33
+
34
+ t.timestamps
35
+ end
36
+
37
+ create_table <%= @report_scopes_table_name %> do |t|
38
+ t.integer :report_id
39
+
40
+ t.string :name
41
+ t.boolean :advanced
42
+
43
+ t.boolean :value_boolean
44
+ t.date :value_date
45
+ t.decimal :value_decimal
46
+ t.integer :value_integer
47
+ t.integer :value_price
48
+ t.string :value_string
49
+
50
+ t.timestamps
51
+ end
52
+
53
+ end
54
+ end
data/db/seeds.rb ADDED
@@ -0,0 +1 @@
1
+ puts "Running effective_reports seeds"
@@ -0,0 +1,18 @@
1
+ module EffectiveReports
2
+ class Engine < ::Rails::Engine
3
+ engine_name 'effective_reports'
4
+
5
+ # Set up our default configuration options.
6
+ initializer 'effective_reports.defaults', before: :load_config_initializers do |app|
7
+ eval File.read("#{config.root}/config/effective_reports.rb")
8
+ end
9
+
10
+ # Include acts_as_reportable concern and allow any ActiveRecord object to call it
11
+ initializer 'effective_reports.active_record' do |app|
12
+ app.config.to_prepare do
13
+ ActiveRecord::Base.extend(ActsAsReportable::Base)
14
+ end
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ module EffectiveReports
2
+ VERSION = '0.1.0'.freeze
3
+ end
@@ -0,0 +1,27 @@
1
+ require 'effective_resources'
2
+ require 'effective_datatables'
3
+ require 'effective_reports/engine'
4
+ require 'effective_reports/version'
5
+
6
+ module EffectiveReports
7
+
8
+ def self.config_keys
9
+ [
10
+ # Database Tables
11
+ :reports_table_name, :report_columns_table_name, :report_scopes_table_name,
12
+
13
+ :reportable_class_names,
14
+
15
+ # Effective Gem
16
+ :layout,
17
+ :mailer, :parent_mailer, :deliver_method, :mailer_layout, :mailer_sender, :mailer_admin, :mailer_subject, :use_effective_email_templates
18
+ ]
19
+ end
20
+
21
+ include EffectiveGem
22
+
23
+ def self.reportable_classes
24
+ Array(reportable_class_names).map(&:safe_constantize).select { |klass| klass.try(:acts_as_reportable?) }
25
+ end
26
+
27
+ end
@@ -0,0 +1,32 @@
1
+ module EffectiveReports
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ include Rails::Generators::Migration
5
+
6
+ desc 'Creates an EffectiveReports initializer in your application.'
7
+
8
+ source_root File.expand_path('../../templates', __FILE__)
9
+
10
+ def self.next_migration_number(dirname)
11
+ if not ActiveRecord::Base.timestamped_migrations
12
+ Time.new.utc.strftime("%Y%m%d%H%M%S")
13
+ else
14
+ '%.3d' % (current_migration_number(dirname) + 1)
15
+ end
16
+ end
17
+
18
+ def copy_initializer
19
+ template ('../' * 3) + 'config/effective_reports.rb', 'config/initializers/effective_reports.rb'
20
+ end
21
+
22
+ def create_migration_file
23
+ @reports_table_name = ':' + EffectiveReports.reports_table_name.to_s
24
+ @report_columns_table_name = ':' + EffectiveReports.report_columns_table_name.to_s
25
+ @report_scopes_table_name = ':' + EffectiveReports.report_scopes_table_name.to_s
26
+
27
+ migration_template ('../' * 3) + 'db/migrate/01_create_effective_reports.rb.erb', 'db/migrate/create_effective_reports.rb'
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,4 @@
1
+ # Visit http://localhost:3000/rails/mailers
2
+
3
+ class EffectiveReportsMailerPreview < ActionMailer::Preview
4
+ end
@@ -0,0 +1,8 @@
1
+ namespace :effective_reports do
2
+
3
+ # bundle exec rake effective_reports:seed
4
+ task seed: :environment do
5
+ load "#{__dir__}/../../db/seeds.rb"
6
+ end
7
+
8
+ end