cm-admin 0.3.0 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
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