effective_reports 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +110 -0
- data/Rakefile +18 -0
- data/app/assets/config/effective_reports_manifest.js +3 -0
- data/app/assets/javascripts/effective_reports/base.js +15 -0
- data/app/assets/javascripts/effective_reports.js +1 -0
- data/app/assets/stylesheets/effective_reports/base.scss +0 -0
- data/app/assets/stylesheets/effective_reports.scss +1 -0
- data/app/controllers/admin/reports_controller.rb +16 -0
- data/app/datatables/admin/effective_reports_datatable.rb +31 -0
- data/app/datatables/effective_report_datatable.rb +21 -0
- data/app/helpers/effective_reports_helper.rb +60 -0
- data/app/mailers/effective/reports_mailer.rb +38 -0
- data/app/models/concerns/acts_as_reportable.rb +72 -0
- data/app/models/effective/report.rb +94 -0
- data/app/models/effective/report_column.rb +89 -0
- data/app/models/effective/report_scope.rb +48 -0
- data/app/views/admin/reports/_form.html.haml +8 -0
- data/app/views/admin/reports/_form_report.html.haml +194 -0
- data/app/views/admin/reports/_layout.html.haml +2 -0
- data/app/views/admin/reports/_report.html.haml +17 -0
- data/config/effective_reports.rb +37 -0
- data/config/routes.rb +16 -0
- data/db/migrate/01_create_effective_reports.rb.erb +54 -0
- data/db/seeds.rb +1 -0
- data/lib/effective_reports/engine.rb +18 -0
- data/lib/effective_reports/version.rb +3 -0
- data/lib/effective_reports.rb +27 -0
- data/lib/generators/effective_reports/install_generator.rb +32 -0
- data/lib/generators/templates/effective_reports_mailer_preview.rb +4 -0
- data/lib/tasks/effective_reports_tasks.rake +8 -0
- 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,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,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
|