cm-admin 0.3.0 → 0.4.3
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.
- checksums.yaml +4 -4
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +2 -1
- data/Gemfile.lock +25 -24
- data/README.md +5 -3
- data/app/assets/stylesheets/cm_admin/base/auth.scss +0 -12
- data/app/assets/stylesheets/cm_admin/base/common.scss +1 -1
- data/app/assets/stylesheets/cm_admin/base/filters.scss +8 -7
- data/app/assets/stylesheets/cm_admin/base/form.scss +7 -73
- data/app/assets/stylesheets/cm_admin/base/navbar.scss +1 -3
- data/app/assets/stylesheets/cm_admin/base/quicksearch.scss +7 -0
- data/app/assets/stylesheets/cm_admin/base/scaffold.scss +39 -2
- data/app/assets/stylesheets/cm_admin/base/show.scss +24 -2
- data/app/assets/stylesheets/cm_admin/base/table.scss +270 -253
- data/app/assets/stylesheets/cm_admin/cm_admin.css.scss +1 -0
- data/app/assets/stylesheets/cm_admin/components/_dropdown-popup.scss +22 -10
- data/app/assets/stylesheets/cm_admin/components/_range.scss +13 -2
- data/app/assets/stylesheets/cm_admin/components/_status-tag.scss +7 -6
- data/app/assets/stylesheets/cm_admin/helpers/_variable.scss +1 -0
- data/app/assets/stylesheets/cm_admin/scaffold.scss +14 -0
- data/app/controllers/cm_admin/application_controller.rb +5 -0
- data/app/controllers/cm_admin/exports_controller.rb +1 -1
- data/app/controllers/cm_admin/static_controller.rb +12 -0
- data/app/helpers/cm_admin/custom_helper.rb +4 -0
- data/app/javascript/packs/cm_admin/application.js +15 -1
- data/app/javascript/packs/cm_admin/filters.js +331 -16
- data/app/javascript/packs/cm_admin/quick_search.js +67 -0
- data/app/javascript/packs/cm_admin/scaffolds.js +30 -1
- data/app/javascript/stylesheets/cm_admin/application.scss +4 -0
- data/app/views/cm_admin/main/_associated_table.html.slim +60 -0
- data/app/views/cm_admin/main/_cm_pagy_nav.html.slim +6 -6
- data/app/views/cm_admin/main/_filters.html.slim +1 -10
- data/app/views/cm_admin/main/_nested_fields.html.slim +7 -0
- data/app/views/cm_admin/main/_nested_table_form.html.slim +6 -0
- data/app/views/cm_admin/main/_table.html.slim +9 -20
- data/app/views/cm_admin/main/_tabs.html.slim +5 -0
- data/app/views/cm_admin/main/_top_navbar.html.slim +12 -6
- data/app/views/cm_admin/main/associated_index.html.slim +6 -0
- data/app/views/cm_admin/main/associated_show.html.slim +6 -0
- data/app/views/cm_admin/main/edit.html.slim +10 -7
- data/app/views/cm_admin/main/index.html.slim +11 -8
- data/app/views/cm_admin/main/show.html.slim +12 -13
- data/app/views/cm_admin/static/error_401.html.slim +4 -0
- data/app/views/layouts/_flash_message.html.slim +9 -0
- data/app/views/layouts/_left_sidebar_nav.html.slim +7 -3
- data/app/views/layouts/_quick_links.html.slim +25 -0
- data/app/views/layouts/cm_admin.html.slim +25 -1
- data/app/views/layouts/static.html.slim +18 -0
- data/bin/console +0 -1
- data/cm_admin.gemspec +2 -1
- data/config/routes.rb +2 -1
- data/config/webpack/environment.js +3 -2
- data/lib/.DS_Store +0 -0
- data/lib/cm_admin/constants.rb +3 -0
- data/lib/cm_admin/model.rb +66 -167
- data/lib/cm_admin/models/action.rb +18 -2
- data/lib/cm_admin/models/cm_show_section.rb +20 -0
- data/lib/cm_admin/models/column.rb +49 -4
- data/lib/cm_admin/models/controller_method.rb +76 -0
- data/lib/cm_admin/models/custom_action.rb +13 -0
- data/lib/cm_admin/models/dsl_method.rb +122 -0
- data/lib/cm_admin/models/export.rb +16 -5
- data/lib/cm_admin/models/field.rb +2 -1
- data/lib/cm_admin/models/filter.rb +67 -2
- data/lib/cm_admin/models/form_field.rb +21 -0
- data/lib/cm_admin/models/tab.rb +13 -0
- data/lib/cm_admin/version.rb +1 -1
- data/lib/cm_admin/view_helpers/column_field_helper.rb +29 -0
- data/lib/cm_admin/view_helpers/field_display_helper.rb +71 -0
- data/lib/cm_admin/view_helpers/filter_helper.rb +190 -0
- data/lib/cm_admin/view_helpers/form_field_helper.rb +21 -4
- data/lib/cm_admin/view_helpers/form_helper.rb +22 -12
- data/lib/cm_admin/view_helpers/manage_column_popup_helper.rb +75 -0
- data/lib/cm_admin/view_helpers/navigation_helper.rb +22 -6
- data/lib/cm_admin/view_helpers/page_info_helper.rb +36 -0
- data/lib/cm_admin/view_helpers.rb +3 -1
- data/lib/cm_admin.rb +3 -1
- data/lib/generators/cm_admin/install_generator.rb +20 -8
- data/package.json +7 -1
- data/tmp/cache/webpacker/last-compilation-digest-development +1 -0
- data/yarn.lock +52 -17
- metadata +46 -9
- data/app/controllers/cm_admin/main_controller.rb +0 -8
- data/lib/c.png +0 -0
- data/lib/cm_admin/view_helpers/field_column_helper.rb +0 -23
- data/lib/generators/cm_admin/templates/cm_admin_initializer.rb +0 -4
- data/yarn-error.log +0 -44
data/lib/cm_admin/model.rb
CHANGED
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
require_relative 'constants'
|
|
2
2
|
require_relative 'models/action'
|
|
3
|
+
require_relative 'models/custom_action'
|
|
3
4
|
require_relative 'models/field'
|
|
5
|
+
require_relative 'models/form_field'
|
|
4
6
|
require_relative 'models/blocks'
|
|
5
7
|
require_relative 'models/column'
|
|
6
8
|
require_relative 'models/filter'
|
|
7
9
|
require_relative 'models/export'
|
|
10
|
+
require_relative 'models/cm_show_section'
|
|
11
|
+
require_relative 'models/tab'
|
|
12
|
+
require_relative 'models/dsl_method'
|
|
13
|
+
require_relative 'models/controller_method'
|
|
8
14
|
require 'pagy'
|
|
9
15
|
require 'axlsx'
|
|
10
|
-
|
|
16
|
+
require 'cocoon'
|
|
11
17
|
|
|
12
18
|
module CmAdmin
|
|
13
19
|
class Model
|
|
14
20
|
include Pagy::Backend
|
|
15
21
|
include Models::Blocks
|
|
16
|
-
|
|
22
|
+
include Models::DslMethod
|
|
23
|
+
include Models::ControllerMethod
|
|
24
|
+
attr_accessor :available_actions, :actions_set, :available_fields, :permitted_fields, :current_action, :params, :filters, :available_tabs
|
|
17
25
|
attr_reader :name, :ar_model
|
|
18
26
|
|
|
19
27
|
# Class variable for storing all actions
|
|
@@ -25,7 +33,8 @@ module CmAdmin
|
|
|
25
33
|
@ar_model = entity
|
|
26
34
|
@available_actions ||= []
|
|
27
35
|
@current_action = nil
|
|
28
|
-
@
|
|
36
|
+
@available_tabs ||= []
|
|
37
|
+
@available_fields ||= {index: [], show: [], edit: {fields: []}, new: {fields: []}}
|
|
29
38
|
@params = nil
|
|
30
39
|
@filters ||= []
|
|
31
40
|
instance_eval(&block) if block_given?
|
|
@@ -39,6 +48,29 @@ module CmAdmin
|
|
|
39
48
|
def all_actions
|
|
40
49
|
@all_actions || []
|
|
41
50
|
end
|
|
51
|
+
|
|
52
|
+
def find_by(search_hash)
|
|
53
|
+
CmAdmin.cm_admin_models.find { |x| x.name == search_hash[:name] }
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def custom_controller_action(action_name, params)
|
|
58
|
+
current_action = CmAdmin::Models::Action.find_by(self, name: action_name.to_s)
|
|
59
|
+
if current_action
|
|
60
|
+
@current_action = current_action
|
|
61
|
+
@ar_object = @ar_model.find(params[:id])
|
|
62
|
+
if @current_action.child_records
|
|
63
|
+
child_records = @ar_object.send(@current_action.child_records)
|
|
64
|
+
@associated_model = CmAdmin::Model.find_by(name: @ar_model.reflect_on_association(@current_action.child_records).klass.name)
|
|
65
|
+
if child_records.is_a? ActiveRecord::Relation
|
|
66
|
+
@associated_ar_object = filter_by(params, child_records)
|
|
67
|
+
else
|
|
68
|
+
@associated_ar_object = child_records
|
|
69
|
+
end
|
|
70
|
+
return @ar_object, @associated_model, @associated_ar_object
|
|
71
|
+
end
|
|
72
|
+
return @ar_object
|
|
73
|
+
end
|
|
42
74
|
end
|
|
43
75
|
|
|
44
76
|
# Insert into actions according to config block
|
|
@@ -53,166 +85,7 @@ module CmAdmin
|
|
|
53
85
|
@actions_set = true
|
|
54
86
|
end
|
|
55
87
|
|
|
56
|
-
def cm_show(&block)
|
|
57
|
-
@current_action = CmAdmin::Models::Action.find_by(self, name: 'show')
|
|
58
|
-
puts "Top of the line"
|
|
59
|
-
yield
|
|
60
|
-
# action.instance_eval(&block)
|
|
61
|
-
puts "End of the line"
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def cm_index(&block)
|
|
65
|
-
@current_action = CmAdmin::Models::Action.find_by(self, name: 'index')
|
|
66
|
-
yield
|
|
67
|
-
# action.instance_eval(&block)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def cm_edit(&block)
|
|
71
|
-
action = CmAdmin::Models::Action.find_by(self, name: 'edit')
|
|
72
|
-
action.instance_eval(&block)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def show(params)
|
|
76
|
-
@current_action = CmAdmin::Models::Action.find_by(self, name: 'show')
|
|
77
|
-
@ar_object = @ar_model.find(params[:id])
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def index(params)
|
|
81
|
-
@current_action = CmAdmin::Models::Action.find_by(self, name: 'index')
|
|
82
|
-
# Based on the params the filter and pagination object to be set
|
|
83
|
-
@ar_object = filter_by(params, filter_params=filter_params(params))
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def filter_by(params, filter_params={}, sort_params={})
|
|
87
|
-
filtered_result = OpenStruct.new
|
|
88
|
-
sort_column = "users.created_at"
|
|
89
|
-
sort_direction = %w[asc desc].include?(sort_params[:sort_direction]) ? sort_params[:sort_direction] : "asc"
|
|
90
|
-
sort_params = {sort_column: sort_column, sort_direction: sort_direction}
|
|
91
|
-
final_data = filtered_data(filter_params)
|
|
92
|
-
pagy, records = pagy(final_data)
|
|
93
|
-
filtered_result.data = records
|
|
94
|
-
filtered_result.pagy = pagy
|
|
95
|
-
# filtered_result.facets = paginate(page, raw_data.size)
|
|
96
|
-
# filtered_result.sort = sort_params
|
|
97
|
-
# filtered_result.facets.sort = sort_params
|
|
98
|
-
return filtered_result
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def filtered_data(filter_params)
|
|
102
|
-
records = self.name.constantize.where(nil)
|
|
103
|
-
if filter_params
|
|
104
|
-
filter_params.each do |scope, scope_value|
|
|
105
|
-
records = self.send("cm_#{scope}", scope_value, records)
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
records
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def cm_search(scope_value, records)
|
|
112
|
-
return nil if scope_value.blank?
|
|
113
|
-
table_name = records.table_name
|
|
114
|
-
|
|
115
|
-
@filters.select{|x| x if x.filter_type.eql?(:search)}.each do |filter|
|
|
116
|
-
terms = scope_value.downcase.split(/\s+/)
|
|
117
|
-
terms = terms.map { |e|
|
|
118
|
-
(e.gsub('*', '%').prepend('%') + '%').gsub(/%+/, '%')
|
|
119
|
-
}
|
|
120
|
-
sql = ""
|
|
121
|
-
filter.db_column_name.each.with_index do |column, i|
|
|
122
|
-
sql.concat("#{table_name}.#{column} ILIKE ?")
|
|
123
|
-
sql.concat(' OR ') unless filter.db_column_name.size.eql?(i+1)
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
records = records.where(
|
|
127
|
-
terms.map { |term|
|
|
128
|
-
sql
|
|
129
|
-
}.join(' AND '),
|
|
130
|
-
*terms.map { |e| [e] * filter.db_column_name.size }.flatten
|
|
131
|
-
)
|
|
132
|
-
end
|
|
133
|
-
records
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
def new(params)
|
|
137
|
-
@ar_object = @ar_model.new
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def edit(params)
|
|
141
|
-
@ar_object = @ar_model.find(params[:id])
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def update(params)
|
|
145
|
-
@ar_object = @ar_model.find(params[:id])
|
|
146
|
-
@ar_object.update(resource_params(params))
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
def create(params)
|
|
150
|
-
@ar_object = @ar_model.new(resource_params(params))
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
def resource_params(params)
|
|
154
|
-
permittable_fields = @permitted_fields || @ar_model.columns.map(&:name).reject { |i| CmAdmin::REJECTABLE_FIELDS.include?(i) }.map(&:to_sym)
|
|
155
|
-
params.require(self.name.underscore.to_sym).permit(*permittable_fields)
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
def page_title(title)
|
|
159
|
-
if @current_action
|
|
160
|
-
@current_action.page_title = title
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
def page_description(description)
|
|
165
|
-
if @current_action
|
|
166
|
-
@current_action.page_description = description
|
|
167
|
-
end
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
def field(field_name, options={})
|
|
171
|
-
puts "For printing field #{field_name}"
|
|
172
|
-
@available_fields[:show] << CmAdmin::Models::Field.new(field_name, options)
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
def column(field_name, options={})
|
|
176
|
-
unless @available_fields[:index].map{|x| x.db_column_name.to_sym}.include?(field_name)
|
|
177
|
-
puts "For printing column #{field_name}"
|
|
178
|
-
@available_fields[:index] << CmAdmin::Models::Column.new(field_name, options)
|
|
179
|
-
end
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
def all_db_columns(options={})
|
|
183
|
-
field_names = self.instance_variable_get(:@ar_model)&.columns&.map{|x| x.name.to_sym}
|
|
184
|
-
if options.include?(:exclude) && field_names
|
|
185
|
-
excluded_fields = (Array.new << options[:exclude]).flatten.map(&:to_sym)
|
|
186
|
-
field_names -= excluded_fields
|
|
187
|
-
end
|
|
188
|
-
field_names.each do |field_name|
|
|
189
|
-
column field_name
|
|
190
|
-
end
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
def self.find_by(search_hash)
|
|
194
|
-
CmAdmin.cm_admin_models.find { |x| x.name == search_hash[:name] }
|
|
195
|
-
end
|
|
196
88
|
|
|
197
|
-
# Custom actions
|
|
198
|
-
# eg
|
|
199
|
-
# class User < ApplicationRecord
|
|
200
|
-
# cm_admin do
|
|
201
|
-
# custom_action name: 'submit', verb: 'post', path: ':id/submit' do
|
|
202
|
-
# def user_submit
|
|
203
|
-
# Code for action here...
|
|
204
|
-
# end
|
|
205
|
-
# end
|
|
206
|
-
# end
|
|
207
|
-
# end
|
|
208
|
-
def custom_action(name: nil, verb: nil, layout: nil, partial: nil, path: nil, &block)
|
|
209
|
-
@available_actions << CmAdmin::Models::Action.new(name: name, verb: verb, layout: layout, partial: partial, path: path)
|
|
210
|
-
self.class.class_eval(&block)
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
def filter(db_column_name, filter_type, options={})
|
|
214
|
-
@filters << CmAdmin::Models::Filter.new(db_column_name: db_column_name, filter_type: filter_type, options: options)
|
|
215
|
-
end
|
|
216
89
|
private
|
|
217
90
|
|
|
218
91
|
# Controller defined for each model
|
|
@@ -227,7 +100,19 @@ module CmAdmin
|
|
|
227
100
|
@model = CmAdmin::Model.find_by(name: controller_name.classify)
|
|
228
101
|
@model.params = params
|
|
229
102
|
@action = CmAdmin::Models::Action.find_by(@model, name: action_name)
|
|
230
|
-
@ar_object = @model.
|
|
103
|
+
@ar_object = @model.try(@action.parent || action_name, params)
|
|
104
|
+
@ar_object, @associated_model, @associated_ar_object = @model.custom_controller_action(action_name, params.permit!) if !@ar_object.present? && params[:id].present?
|
|
105
|
+
nested_tables = @model.available_fields[:new].except(:fields).keys
|
|
106
|
+
nested_tables += @model.available_fields[:edit].except(:fields).keys
|
|
107
|
+
@reflections = @model.ar_model.reflect_on_all_associations
|
|
108
|
+
nested_tables.each do |table_name|
|
|
109
|
+
reflection = @reflections.select {|x| x if x.name == table_name}.first
|
|
110
|
+
if reflection.macro == :has_many
|
|
111
|
+
@ar_object.send(table_name).build if action_name == "new" || action_name == "edit"
|
|
112
|
+
else
|
|
113
|
+
@ar_object.send(('build_' + table_name.to_s).to_sym) if action_name == "new"
|
|
114
|
+
end
|
|
115
|
+
end
|
|
231
116
|
respond_to do |format|
|
|
232
117
|
if %w(show index new edit).include?(action_name)
|
|
233
118
|
if request.xhr? && action_name.eql?('index')
|
|
@@ -241,11 +126,19 @@ module CmAdmin
|
|
|
241
126
|
else
|
|
242
127
|
format.html { render '/cm_admin/main/new' }
|
|
243
128
|
end
|
|
129
|
+
elsif action.class == CmAdmin::Models::CustomAction
|
|
130
|
+
redirect_url = request.referrer || "/cm_admin/#{@model.ar_model.table_name}/#{@ar_object.id}"
|
|
131
|
+
data = @action.parent == "index" ? @ar_object.data : @ar_object
|
|
132
|
+
if @action.code_block.call(@ar_object)
|
|
133
|
+
format.html { redirect_to redirect_url }
|
|
134
|
+
else
|
|
135
|
+
format.html { redirect_to redirect_url }
|
|
136
|
+
end
|
|
244
137
|
elsif action.layout.present?
|
|
245
|
-
if action.partial.present?
|
|
246
|
-
render partial: action.partial
|
|
138
|
+
if request.xhr? && action.partial.present?
|
|
139
|
+
format.html { render partial: action.partial }
|
|
247
140
|
else
|
|
248
|
-
render
|
|
141
|
+
format.html { render action.layout }
|
|
249
142
|
end
|
|
250
143
|
end
|
|
251
144
|
end
|
|
@@ -256,7 +149,13 @@ module CmAdmin
|
|
|
256
149
|
end
|
|
257
150
|
|
|
258
151
|
def filter_params(params)
|
|
259
|
-
|
|
152
|
+
# OPTIMIZE: Need to check if we can permit the filter_params in a better way
|
|
153
|
+
date_columns = @filters.select{|x| x.filter_type.eql?(:date)}.map(&:db_column_name)
|
|
154
|
+
range_columns = @filters.select{|x| x.filter_type.eql?(:range)}.map(&:db_column_name)
|
|
155
|
+
single_select_columns = @filters.select{|x| x.filter_type.eql?(:single_select)}.map(&:db_column_name)
|
|
156
|
+
multi_select_columns = @filters.select{|x| x.filter_type.eql?(:multi_select)}.map{|x| Hash["#{x.db_column_name}", []]}
|
|
157
|
+
|
|
158
|
+
params.require(:filters).permit(:search, date: date_columns, range: range_columns, single_select: single_select_columns, multi_select: multi_select_columns) if params[:filters]
|
|
260
159
|
end
|
|
261
160
|
end
|
|
262
161
|
end
|
|
@@ -4,12 +4,28 @@ module CmAdmin
|
|
|
4
4
|
module Models
|
|
5
5
|
class Action
|
|
6
6
|
include Actions::Blocks
|
|
7
|
-
attr_accessor :name, :verb, :layout, :partial, :path, :page_title, :page_description
|
|
7
|
+
attr_accessor :name, :verb, :layout_type, :layout, :partial, :path, :page_title, :page_description, :child_records, :is_nested_field, :nested_table_name, :parent, :display_if, :route_type, :code_block
|
|
8
8
|
|
|
9
|
-
def initialize(attributes = {})
|
|
9
|
+
def initialize(attributes = {}, &block)
|
|
10
|
+
if attributes[:layout_type].present? && attributes[:layout].nil? && attributes[:partial].nil?
|
|
11
|
+
case attributes[:layout_type]
|
|
12
|
+
when 'cm_association_index'
|
|
13
|
+
attributes[:layout] = '/cm_admin/main/associated_index'
|
|
14
|
+
attributes[:partial] = '/cm_admin/main/associated_table'
|
|
15
|
+
when 'cm_association_show'
|
|
16
|
+
attributes[:layout] = '/cm_admin/main/associated_show'
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
set_default_values
|
|
10
20
|
attributes.each do |key, value|
|
|
11
21
|
self.send("#{key.to_s}=", value)
|
|
12
22
|
end
|
|
23
|
+
self.send("code_block=", block) if block_given?
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def set_default_values
|
|
27
|
+
self.is_nested_field = false
|
|
28
|
+
self.display_if = true
|
|
13
29
|
end
|
|
14
30
|
|
|
15
31
|
class << self
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module CmAdmin
|
|
2
|
+
module Models
|
|
3
|
+
class CmShowSection
|
|
4
|
+
|
|
5
|
+
attr_accessor :section_name, :available_section_fields
|
|
6
|
+
|
|
7
|
+
def initialize(section_name, &block)
|
|
8
|
+
@available_section_fields = []
|
|
9
|
+
@section_name = section_name
|
|
10
|
+
puts "-- reached here --"
|
|
11
|
+
instance_eval(&block)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def field(field_name, options={})
|
|
15
|
+
puts "For printing field #{field_name}"
|
|
16
|
+
@available_section_fields << CmAdmin::Models::Field.new(field_name, options)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -1,14 +1,59 @@
|
|
|
1
1
|
module CmAdmin
|
|
2
2
|
module Models
|
|
3
3
|
class Column
|
|
4
|
-
attr_accessor :
|
|
4
|
+
attr_accessor :field_name, :field_type, :header, :format, :prefix, :suffix, :exportable, :round,
|
|
5
|
+
:cm_css_class, :link, :url, :custom_method, :helper_method, :managable, :lockable
|
|
5
6
|
|
|
6
|
-
def initialize(
|
|
7
|
-
@
|
|
7
|
+
def initialize(field_name, attributes = {})
|
|
8
|
+
@field_name = field_name
|
|
9
|
+
set_default_values
|
|
8
10
|
attributes.each do |key, value|
|
|
9
11
|
self.send("#{key.to_s}=", value)
|
|
10
12
|
end
|
|
11
|
-
|
|
13
|
+
|
|
14
|
+
#formatting header (either field_name or value present in header attribute)
|
|
15
|
+
self.send("header=", format_header)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
#returns a string value as a header (either field_name or value present in header attribute)
|
|
19
|
+
def format_header
|
|
20
|
+
self.header.present? ? self.header.to_s.gsub(/_/, ' ')&.upcase : self.field_name.to_s.gsub(/_/, ' ').upcase
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def set_default_values
|
|
24
|
+
self.exportable = true
|
|
25
|
+
self.managable = true
|
|
26
|
+
self.lockable = false
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
#formatting value for different data types
|
|
30
|
+
def self.format_data_type(column, value)
|
|
31
|
+
case column.column_type
|
|
32
|
+
when :string
|
|
33
|
+
if column.format.present?
|
|
34
|
+
column.format = [column.format] if column.format.is_a? String
|
|
35
|
+
column.format.each do |formatter|
|
|
36
|
+
value = value.send(formatter)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
when :datetime
|
|
40
|
+
format_value = column.format.present? ? column.format.to_s : '%d/%m/%Y'
|
|
41
|
+
value = value.strftime(format_value)
|
|
42
|
+
when :enum
|
|
43
|
+
value = value.titleize
|
|
44
|
+
when :decimal
|
|
45
|
+
round_to = column.round.present? ? column.round.to_i : 2
|
|
46
|
+
value = value.round(round_to)
|
|
47
|
+
when :custom
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
return value
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class << self
|
|
54
|
+
def find_by(model, search_hash)
|
|
55
|
+
model.available_fields.find { |i| i.name == search_hash[:name] }
|
|
56
|
+
end
|
|
12
57
|
end
|
|
13
58
|
|
|
14
59
|
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
module CmAdmin
|
|
2
|
+
module Models
|
|
3
|
+
module ControllerMethod
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
def show(params)
|
|
7
|
+
@current_action = CmAdmin::Models::Action.find_by(self, name: 'show')
|
|
8
|
+
@ar_object = @ar_model.find(params[:id])
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def index(params)
|
|
12
|
+
@current_action = CmAdmin::Models::Action.find_by(self, name: 'index')
|
|
13
|
+
# Based on the params the filter and pagination object to be set
|
|
14
|
+
@ar_object = filter_by(params, nil, filter_params(params))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def new(params)
|
|
18
|
+
@current_action = CmAdmin::Models::Action.find_by(self, name: 'new')
|
|
19
|
+
@ar_object = @ar_model.new
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def edit(params)
|
|
23
|
+
@current_action = CmAdmin::Models::Action.find_by(self, name: 'edit')
|
|
24
|
+
@ar_object = @ar_model.find(params[:id])
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def update(params)
|
|
28
|
+
@ar_object = @ar_model.find(params[:id])
|
|
29
|
+
@ar_object.assign_attributes(resource_params(params))
|
|
30
|
+
@ar_object
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def create(params)
|
|
35
|
+
@ar_object = @ar_model.new(resource_params(params))
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def filter_by(params, records, filter_params={}, sort_params={})
|
|
39
|
+
filtered_result = OpenStruct.new
|
|
40
|
+
sort_column = "created_at"
|
|
41
|
+
sort_direction = %w[asc desc].include?(sort_params[:sort_direction]) ? sort_params[:sort_direction] : "asc"
|
|
42
|
+
sort_params = {sort_column: sort_column, sort_direction: sort_direction}
|
|
43
|
+
records = self.name.constantize.where(nil) if records.nil?
|
|
44
|
+
final_data = CmAdmin::Models::Filter.filtered_data(filter_params, records, @filters)
|
|
45
|
+
pagy, records = pagy(final_data)
|
|
46
|
+
filtered_result.data = records
|
|
47
|
+
filtered_result.pagy = pagy
|
|
48
|
+
# filtered_result.facets = paginate(page, raw_data.size)
|
|
49
|
+
# filtered_result.sort = sort_params
|
|
50
|
+
# filtered_result.facets.sort = sort_params
|
|
51
|
+
return filtered_result
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def resource_params(params)
|
|
55
|
+
permittable_fields = @permitted_fields || @ar_model.columns.map(&:name).reject { |i| CmAdmin::REJECTABLE_FIELDS.include?(i) }.map(&:to_sym)
|
|
56
|
+
permittable_fields += @ar_model.reflect_on_all_attachments.map {|x|
|
|
57
|
+
if x.class.name.include?('HasOne')
|
|
58
|
+
x.name
|
|
59
|
+
elsif x.class.name.include?('HasMany')
|
|
60
|
+
Hash[x.name.to_s, []]
|
|
61
|
+
end
|
|
62
|
+
}.compact
|
|
63
|
+
nested_tables = self.available_fields[:new].except(:fields).keys
|
|
64
|
+
nested_tables += self.available_fields[:edit].except(:fields).keys
|
|
65
|
+
nested_fields = nested_tables.map {|table|
|
|
66
|
+
Hash[
|
|
67
|
+
table.to_s + '_attributes',
|
|
68
|
+
table.to_s.singularize.titleize.constantize.columns.map(&:name).reject { |i| CmAdmin::REJECTABLE_FIELDS.include?(i) }.map(&:to_sym) + [:id, :_destroy]
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
permittable_fields += nested_fields
|
|
72
|
+
params.require(self.name.underscore.to_sym).permit(*permittable_fields)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
module CmAdmin
|
|
2
|
+
module Models
|
|
3
|
+
module DslMethod
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
def cm_index(page_title: nil ,page_description: nil, &block)
|
|
7
|
+
@current_action = CmAdmin::Models::Action.find_by(self, name: 'index')
|
|
8
|
+
@current_action.page_title = page_title
|
|
9
|
+
@current_action.page_description = page_description
|
|
10
|
+
yield
|
|
11
|
+
# action.instance_eval(&block)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def cm_show(page_title: nil,page_description: nil,&block)
|
|
15
|
+
@current_action = CmAdmin::Models::Action.find_by(self, name: 'show')
|
|
16
|
+
@current_action.page_title = page_title
|
|
17
|
+
@current_action.page_description = page_description
|
|
18
|
+
yield
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def cm_edit(page_title: nil,page_description: nil, &block)
|
|
22
|
+
@current_action = CmAdmin::Models::Action.find_by(self, name: 'edit')
|
|
23
|
+
@current_action.page_title = page_title
|
|
24
|
+
@current_action.page_description = page_description
|
|
25
|
+
yield
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def cm_new(page_title: nil,page_description: nil,&block)
|
|
29
|
+
@current_action = CmAdmin::Models::Action.find_by(self, name: 'new')
|
|
30
|
+
@current_action.page_title = page_title
|
|
31
|
+
@current_action.page_description = page_description
|
|
32
|
+
yield
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def page_title(title)
|
|
36
|
+
if @current_action
|
|
37
|
+
@current_action.page_title = title
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def page_description(description)
|
|
42
|
+
if @current_action
|
|
43
|
+
@current_action.page_description = description
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def tab(tab_name, custom_action, associated_model: nil, layout_type: nil, layout: nil, partial: nil, &block)
|
|
48
|
+
if custom_action.to_s == ''
|
|
49
|
+
@current_action = CmAdmin::Models::Action.find_by(self, name: 'show')
|
|
50
|
+
@available_tabs << CmAdmin::Models::Tab.new(tab_name, '', &block)
|
|
51
|
+
else
|
|
52
|
+
action = CmAdmin::Models::Action.new(name: custom_action.to_s, verb: :get, path: ':id/'+custom_action, layout_type: layout_type, layout: layout, partial: partial, child_records: associated_model)
|
|
53
|
+
@available_actions << action
|
|
54
|
+
@current_action = action
|
|
55
|
+
@available_tabs << CmAdmin::Models::Tab.new(tab_name, custom_action, &block)
|
|
56
|
+
end
|
|
57
|
+
yield if block
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def cm_show_section(section_name, &block)
|
|
61
|
+
@available_fields[@current_action.name.to_sym] ||= []
|
|
62
|
+
@available_fields[@current_action.name.to_sym] << CmAdmin::Models::CmShowSection.new(section_name, &block)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def form_field(field_name, options={}, arg=nil)
|
|
66
|
+
unless @current_action.is_nested_field
|
|
67
|
+
@available_fields[@current_action.name.to_sym][:fields] << CmAdmin::Models::FormField.new(field_name, options[:input_type], options)
|
|
68
|
+
else
|
|
69
|
+
@available_fields[@current_action.name.to_sym][@current_action.nested_table_name] ||= []
|
|
70
|
+
@available_fields[@current_action.name.to_sym][@current_action.nested_table_name] << CmAdmin::Models::FormField.new(field_name, options[:input_type], options)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def nested_form_field(field_name, &block)
|
|
75
|
+
@current_action.is_nested_field = true
|
|
76
|
+
@current_action.nested_table_name = field_name
|
|
77
|
+
yield
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def column(field_name, options={})
|
|
81
|
+
@available_fields[@current_action.name.to_sym] ||= []
|
|
82
|
+
if @available_fields[@current_action.name.to_sym].select{|x| x.lockable}.size > 0 && options[:lockable]
|
|
83
|
+
raise "Only one column can be locked in a table."
|
|
84
|
+
end
|
|
85
|
+
unless @available_fields[@current_action.name.to_sym].map{|x| x.field_name.to_sym}.include?(field_name)
|
|
86
|
+
@available_fields[@current_action.name.to_sym] << CmAdmin::Models::Column.new(field_name, options)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def all_db_columns(options={})
|
|
91
|
+
field_names = self.instance_variable_get(:@ar_model)&.columns&.map{|x| x.name.to_sym}
|
|
92
|
+
if options.include?(:exclude) && field_names
|
|
93
|
+
excluded_fields = (Array.new << options[:exclude]).flatten.map(&:to_sym)
|
|
94
|
+
field_names -= excluded_fields
|
|
95
|
+
end
|
|
96
|
+
field_names.each do |field_name|
|
|
97
|
+
column field_name
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Custom actions
|
|
102
|
+
# eg
|
|
103
|
+
# class User < ApplicationRecord
|
|
104
|
+
# cm_admin do
|
|
105
|
+
# custom_action name: 'submit', verb: 'post', path: ':id/submit' do
|
|
106
|
+
# def user_submit
|
|
107
|
+
# Code for action here...
|
|
108
|
+
# end
|
|
109
|
+
# end
|
|
110
|
+
# end
|
|
111
|
+
# end
|
|
112
|
+
def custom_action(name: nil, verb: nil, layout: nil, partial: nil, path: nil, display_if: lambda { |arg| return true }, route_type: nil, &block)
|
|
113
|
+
@available_actions << CmAdmin::Models::CustomAction.new(name: name, verb: verb, layout: layout, partial: partial, path: path, parent: self.current_action.name, display_if: display_if, route_type: route_type, &block)
|
|
114
|
+
# self.class.class_eval(&block)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def filter(db_column_name, filter_type, options={})
|
|
118
|
+
@filters << CmAdmin::Models::Filter.new(db_column_name: db_column_name, filter_type: filter_type, options: options)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -2,19 +2,30 @@ module CmAdmin
|
|
|
2
2
|
module Models
|
|
3
3
|
class Export
|
|
4
4
|
class << self
|
|
5
|
-
def generate_excel(klass_name, columns = [])
|
|
5
|
+
def generate_excel(klass_name, columns = [], helpers)
|
|
6
6
|
klass = klass_name.constantize
|
|
7
|
-
|
|
7
|
+
model = CmAdmin::Model.find_by({name: klass_name})
|
|
8
|
+
records = get_records(klass, model, columns, helpers)
|
|
8
9
|
file_path = "#{Rails.root}/tmp/#{klass}_data_#{DateTime.now.strftime("%Y-%m-%d_%H-%M-%S")}.xlsx"
|
|
9
10
|
create_workbook(records, columns, file_path)
|
|
10
11
|
return file_path
|
|
11
12
|
end
|
|
12
13
|
|
|
13
|
-
def get_records(klass, columns)
|
|
14
|
+
def get_records(klass, model, columns, helpers)
|
|
14
15
|
records = klass
|
|
16
|
+
custom_fields = model.available_fields[:index].map{|field| field if field.field_type == :custom}.compact
|
|
17
|
+
normal_fields = model.available_fields[:index].map{|field| field unless field.field_type == :custom}.compact
|
|
15
18
|
deserialized_columns = CmAdmin::Utils.deserialize_csv_columns(columns, :as_json_params)
|
|
16
19
|
# This includes isn't recursve, a full solution should be recursive
|
|
17
|
-
|
|
20
|
+
records_arr = []
|
|
21
|
+
records.includes(deserialized_columns[:include].keys).find_each do |record|
|
|
22
|
+
record_hash = record.as_json({only: normal_fields.map(&:field_name)})
|
|
23
|
+
custom_fields.each do |field|
|
|
24
|
+
record_hash[field.field_name.to_sym] = helpers.send(field.helper_method, record, field.field_name)
|
|
25
|
+
end
|
|
26
|
+
records_arr << record_hash
|
|
27
|
+
end
|
|
28
|
+
records_arr
|
|
18
29
|
end
|
|
19
30
|
|
|
20
31
|
def create_workbook(records, class_name, file_path)
|
|
@@ -34,7 +45,7 @@ module CmAdmin
|
|
|
34
45
|
end
|
|
35
46
|
|
|
36
47
|
def exportable_columns(klass)
|
|
37
|
-
klass.available_fields[:index].map{|x| x.exportable ? x.
|
|
48
|
+
klass.available_fields[:index].map{|x| x.exportable ? x.field_name : ""}.reject { |c| c.empty? }
|
|
38
49
|
end
|
|
39
50
|
|
|
40
51
|
end
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
module CmAdmin
|
|
2
2
|
module Models
|
|
3
3
|
class Field
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
attr_accessor :field_name, :label, :header, :field_type, :format, :precision, :helper_method, :preview, :custom_link, :precision
|
|
5
6
|
|
|
6
7
|
def initialize(field_name, attributes = {})
|
|
7
8
|
@field_name = field_name
|