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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/CODE_OF_CONDUCT.md +74 -0
  3. data/Gemfile +2 -1
  4. data/Gemfile.lock +25 -24
  5. data/README.md +5 -3
  6. data/app/assets/stylesheets/cm_admin/base/auth.scss +0 -12
  7. data/app/assets/stylesheets/cm_admin/base/common.scss +1 -1
  8. data/app/assets/stylesheets/cm_admin/base/filters.scss +8 -7
  9. data/app/assets/stylesheets/cm_admin/base/form.scss +7 -73
  10. data/app/assets/stylesheets/cm_admin/base/navbar.scss +1 -3
  11. data/app/assets/stylesheets/cm_admin/base/quicksearch.scss +7 -0
  12. data/app/assets/stylesheets/cm_admin/base/scaffold.scss +39 -2
  13. data/app/assets/stylesheets/cm_admin/base/show.scss +24 -2
  14. data/app/assets/stylesheets/cm_admin/base/table.scss +270 -253
  15. data/app/assets/stylesheets/cm_admin/cm_admin.css.scss +1 -0
  16. data/app/assets/stylesheets/cm_admin/components/_dropdown-popup.scss +22 -10
  17. data/app/assets/stylesheets/cm_admin/components/_range.scss +13 -2
  18. data/app/assets/stylesheets/cm_admin/components/_status-tag.scss +7 -6
  19. data/app/assets/stylesheets/cm_admin/helpers/_variable.scss +1 -0
  20. data/app/assets/stylesheets/cm_admin/scaffold.scss +14 -0
  21. data/app/controllers/cm_admin/application_controller.rb +5 -0
  22. data/app/controllers/cm_admin/exports_controller.rb +1 -1
  23. data/app/controllers/cm_admin/static_controller.rb +12 -0
  24. data/app/helpers/cm_admin/custom_helper.rb +4 -0
  25. data/app/javascript/packs/cm_admin/application.js +15 -1
  26. data/app/javascript/packs/cm_admin/filters.js +331 -16
  27. data/app/javascript/packs/cm_admin/quick_search.js +67 -0
  28. data/app/javascript/packs/cm_admin/scaffolds.js +30 -1
  29. data/app/javascript/stylesheets/cm_admin/application.scss +4 -0
  30. data/app/views/cm_admin/main/_associated_table.html.slim +60 -0
  31. data/app/views/cm_admin/main/_cm_pagy_nav.html.slim +6 -6
  32. data/app/views/cm_admin/main/_filters.html.slim +1 -10
  33. data/app/views/cm_admin/main/_nested_fields.html.slim +7 -0
  34. data/app/views/cm_admin/main/_nested_table_form.html.slim +6 -0
  35. data/app/views/cm_admin/main/_table.html.slim +9 -20
  36. data/app/views/cm_admin/main/_tabs.html.slim +5 -0
  37. data/app/views/cm_admin/main/_top_navbar.html.slim +12 -6
  38. data/app/views/cm_admin/main/associated_index.html.slim +6 -0
  39. data/app/views/cm_admin/main/associated_show.html.slim +6 -0
  40. data/app/views/cm_admin/main/edit.html.slim +10 -7
  41. data/app/views/cm_admin/main/index.html.slim +11 -8
  42. data/app/views/cm_admin/main/show.html.slim +12 -13
  43. data/app/views/cm_admin/static/error_401.html.slim +4 -0
  44. data/app/views/layouts/_flash_message.html.slim +9 -0
  45. data/app/views/layouts/_left_sidebar_nav.html.slim +7 -3
  46. data/app/views/layouts/_quick_links.html.slim +25 -0
  47. data/app/views/layouts/cm_admin.html.slim +25 -1
  48. data/app/views/layouts/static.html.slim +18 -0
  49. data/bin/console +0 -1
  50. data/cm_admin.gemspec +2 -1
  51. data/config/routes.rb +2 -1
  52. data/config/webpack/environment.js +3 -2
  53. data/lib/.DS_Store +0 -0
  54. data/lib/cm_admin/constants.rb +3 -0
  55. data/lib/cm_admin/model.rb +66 -167
  56. data/lib/cm_admin/models/action.rb +18 -2
  57. data/lib/cm_admin/models/cm_show_section.rb +20 -0
  58. data/lib/cm_admin/models/column.rb +49 -4
  59. data/lib/cm_admin/models/controller_method.rb +76 -0
  60. data/lib/cm_admin/models/custom_action.rb +13 -0
  61. data/lib/cm_admin/models/dsl_method.rb +122 -0
  62. data/lib/cm_admin/models/export.rb +16 -5
  63. data/lib/cm_admin/models/field.rb +2 -1
  64. data/lib/cm_admin/models/filter.rb +67 -2
  65. data/lib/cm_admin/models/form_field.rb +21 -0
  66. data/lib/cm_admin/models/tab.rb +13 -0
  67. data/lib/cm_admin/version.rb +1 -1
  68. data/lib/cm_admin/view_helpers/column_field_helper.rb +29 -0
  69. data/lib/cm_admin/view_helpers/field_display_helper.rb +71 -0
  70. data/lib/cm_admin/view_helpers/filter_helper.rb +190 -0
  71. data/lib/cm_admin/view_helpers/form_field_helper.rb +21 -4
  72. data/lib/cm_admin/view_helpers/form_helper.rb +22 -12
  73. data/lib/cm_admin/view_helpers/manage_column_popup_helper.rb +75 -0
  74. data/lib/cm_admin/view_helpers/navigation_helper.rb +22 -6
  75. data/lib/cm_admin/view_helpers/page_info_helper.rb +36 -0
  76. data/lib/cm_admin/view_helpers.rb +3 -1
  77. data/lib/cm_admin.rb +3 -1
  78. data/lib/generators/cm_admin/install_generator.rb +20 -8
  79. data/package.json +7 -1
  80. data/tmp/cache/webpacker/last-compilation-digest-development +1 -0
  81. data/yarn.lock +52 -17
  82. metadata +46 -9
  83. data/app/controllers/cm_admin/main_controller.rb +0 -8
  84. data/lib/c.png +0 -0
  85. data/lib/cm_admin/view_helpers/field_column_helper.rb +0 -23
  86. data/lib/generators/cm_admin/templates/cm_admin_initializer.rb +0 -4
  87. data/yarn-error.log +0 -44
@@ -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
- attr_accessor :available_actions, :actions_set, :available_fields, :permitted_fields, :current_action, :params, :filters
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
- @available_fields ||= {index: [], show: [], edit: [], new: []}
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.send(action_name, params)
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, layout: action.layout
138
+ if request.xhr? && action.partial.present?
139
+ format.html { render partial: action.partial }
247
140
  else
248
- render layout: action.layout
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
- params.require(:filters).permit(:search) if params[:filters]
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 :db_column_name, :column_type, :header, :format, :prefix, :exportable
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(db_column_name, attributes = {})
7
- @db_column_name = db_column_name
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
- @exportable = true if attributes[:exportable].nil?
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,13 @@
1
+ require_relative 'actions/blocks'
2
+
3
+ module CmAdmin
4
+ module Models
5
+ class CustomAction < Action
6
+ class << self
7
+ def find_by(model, search_hash)
8
+ model.available_actions.find { |i| i.name == search_hash[:name] }
9
+ end
10
+ end
11
+ end
12
+ end
13
+ 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
- records = get_records(klass, columns)
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
- records.includes(deserialized_columns[:include].keys).find_each.as_json(deserialized_columns)
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.db_column_name : ""}.reject { |c| c.empty? }
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
- attr_accessor :field_name, :label, :header
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