cm-admin 1.1.6 → 1.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop-https---raw-githubusercontent-com-commutatus-cm-linters-main-rubocop-yml +20 -0
  3. data/Gemfile.lock +60 -60
  4. data/app/assets/javascripts/cm_admin/application.js +8 -3
  5. data/app/assets/javascripts/cm_admin/bulk_actions.js +36 -0
  6. data/app/assets/javascripts/cm_admin/custom.js +0 -0
  7. data/app/assets/javascripts/cm_admin/scaffolds.js +1 -1
  8. data/app/assets/stylesheets/cm_admin/base/navbar.scss +3 -2
  9. data/app/assets/stylesheets/cm_admin/cm_admin.css.scss +1 -0
  10. data/app/assets/stylesheets/cm_admin/components/_buttons.scss +17 -11
  11. data/app/assets/stylesheets/cm_admin/dependency/jquery-jgrowl.min.css +1 -0
  12. data/app/assets/stylesheets/cm_admin/helpers/_variable.scss +31 -30
  13. data/app/controllers/cm_admin/resource_controller.rb +29 -10
  14. data/app/helpers/cm_admin/application_helper.rb +4 -0
  15. data/app/javascript/packs/cm_admin/application.js +1 -0
  16. data/app/models/concerns/cm_admin/bulk_action_processor.rb +29 -0
  17. data/app/views/cm_admin/main/_associated_table.html.slim +19 -9
  18. data/app/views/cm_admin/main/_table.html.slim +27 -14
  19. data/app/views/cm_admin/main/index.html.slim +1 -1
  20. data/app/views/layouts/_cm_flash_message.html.slim +3 -3
  21. data/app/views/layouts/_custom_action_modals.html.slim +4 -1
  22. data/lib/cm_admin/model.rb +3 -1
  23. data/lib/cm_admin/models/action.rb +10 -4
  24. data/lib/cm_admin/models/bulk_action.rb +18 -0
  25. data/lib/cm_admin/models/dsl_method.rb +9 -0
  26. data/lib/cm_admin/models/filter.rb +55 -29
  27. data/lib/cm_admin/models/form_field.rb +18 -3
  28. data/lib/cm_admin/models/utils/helpers.rb +14 -0
  29. data/lib/cm_admin/version.rb +1 -1
  30. data/lib/cm_admin/view_helpers/filter_helper.rb +1 -1
  31. data/lib/cm_admin/view_helpers/form_field_helper.rb +16 -17
  32. data/lib/cm_admin/view_helpers/page_info_helper.rb +10 -0
  33. metadata +9 -2
@@ -14,25 +14,35 @@
14
14
  / i.fa.fa-columns.bolder
15
15
  / span
16
16
  / i.fa.fa-angle-down
17
-
17
+ - if flash[:alert].present?
18
+ .alert.alert-danger role="alert"
19
+ = flash[:alert].html_safe
20
+ - elsif flash[:notice].present?
21
+ .alert.alert-success
22
+ = flash[:notice].html_safe
23
+ - bulk_actions = actions_filter(@associated_model, :bulk_action)
24
+ - if bulk_actions.present?
25
+ .table-top.hidden data-section="bulk-action"
26
+ - bulk_actions.each do |action|
27
+ = custom_action_items(action, 'index')
18
28
  .new-admin-table.scrollable
19
29
  table.cm-table
20
30
  thead.cm-table__header
21
31
  tr.header-row
22
- // To be added once bulk-select is finalized
23
- / th.check-box-space
24
- / span
25
- / input.cm-checkbox type="checkbox"
32
+ - if bulk_actions.present?
33
+ th.check-box-space
34
+ span
35
+ input.cm-checkbox type="checkbox" data-behaviour="bulk-action-select-all"
26
36
  - @model.available_fields[@action.name.to_sym].each do |column|
27
37
  - if column.display_if.call(Current.user) && column.viewable
28
38
  th = column.header
29
39
  tbody.cm-table__body
30
40
  - @associated_ar_object.data.each do |ar_object|
31
41
  tr.body-row
32
- // To be added once bulk-select is finalized
33
- / td.check-box-space
34
- / span
35
- / input.cm-checkbox type="checkbox"
42
+ - if bulk_actions.present?
43
+ td.check-box-space
44
+ span
45
+ input.cm-checkbox type="checkbox" data-behaviour="bulk-action-checkbox" data-ar-object-id="#{ar_object.id}"
36
46
  - @model.available_fields[@action.name.to_sym].each_with_index do |column, index|
37
47
  - if column.display_if.call(Current.user) && column.viewable
38
48
  td class="text-ellipsis"
@@ -1,28 +1,41 @@
1
1
  .table-top
2
2
  p.table-top__total-count = "#{humanized_ar_collection_count(@ar_object.pagy.count, @model.ar_model.table_name)}"
3
- // .table-top__column-action
4
- // button.secondary-btn.column-btn data-bs-target="#columnActionModal" data-bs-toggle="modal"
5
- // span
6
- // i.fa.fa-columns.bolder
7
- // span
8
- // i.fa.fa-angle-down
3
+ / .table-top__column-action
4
+ / button.secondary-btn.column-btn data-bs-target="#columnActionModal" data-bs-toggle="modal"
5
+ / span
6
+ / i.fa.fa-columns.bolder
7
+ / span
8
+ / i.fa.fa-angle-down
9
+ - if flash[:alert].present?
10
+ .alert.alert-danger role="alert"
11
+ = flash[:alert].html_safe
12
+ - elsif flash[:notice].present?
13
+ .alert.alert-success
14
+ = flash[:notice].html_safe
15
+
16
+ - bulk_actions = actions_filter(@model, :bulk_action)
17
+ - if bulk_actions.present?
18
+ .table-top.hidden data-section="bulk-action"
19
+ - bulk_actions.each do |action|
20
+ = custom_action_items(action, 'index')
9
21
  .new-admin-table
10
22
  table.cm-table
11
23
  thead.cm-table__header
12
24
  tr.header-row
13
- // Select all checkbox feature to be added later
14
- / th.check-box-space
15
- / span
16
- / input.cm-checkbox type="checkbox"
25
+ - if bulk_actions.present?
26
+ th.check-box-space
27
+ span
28
+ input.cm-checkbox type="checkbox" data-behaviour="bulk-action-select-all"
17
29
  - @model.available_fields[:index].each do |column|
18
30
  - if column.display_if.call(Current.user) && column.viewable
19
31
  th = column.header
20
32
  tbody.cm-table__body
21
33
  - @ar_object.data.each do |ar_object|
22
34
  tr.body-row
23
- / td.check-box-space
24
- / span
25
- / input.cm-checkbox type="checkbox"
35
+ - if bulk_actions.present?
36
+ td.check-box-space
37
+ span
38
+ input.cm-checkbox type="checkbox" data-behaviour="bulk-action-checkbox" data-ar-object-id="#{ar_object.id}"
26
39
  - @model.available_fields[:index].each_with_index do |column, index|
27
40
  - if column.display_if.call(Current.user) && column.viewable
28
41
  td.text-ellipsis
@@ -41,4 +54,4 @@
41
54
  .cm-pagination__rhs
42
55
  == render partial: 'cm_admin/main/cm_pagy_nav', locals: { pagy: @ar_object.pagy }
43
56
 
44
- = render partial: 'cm_admin/main/member_custom_action_modal', locals: { cm_model: @model, ar_collection: @ar_object }
57
+ / = render partial: 'cm_admin/main/member_custom_action_modal', locals: { cm_model: @model, ar_collection: @ar_object }
@@ -1,3 +1,4 @@
1
+
1
2
  .cm-index-page.cm-page-container
2
3
  .sticky-container.page-top-bar
3
4
  == render 'cm_admin/main/top_navbar'
@@ -9,7 +10,6 @@
9
10
  == render @action.partial
10
11
  - else
11
12
  == render 'cm_admin/main/table'
12
-
13
13
  = column_pop_up(@model)
14
14
  = manage_column_pop_up(@model)
15
15
 
@@ -1,9 +1,9 @@
1
1
  - if flash[:notice].present?
2
2
  javascript:
3
- $.jGrowl("#{flash[:notice]}", {theme: 'notice'})
3
+ $.jGrowl("#{flash[:notice]}", { theme: 'notice' })
4
4
  - elsif flash[:success].present?
5
5
  javascript:
6
- $.jGrowl("#{flash[:success]}", {theme: 'success'})
6
+ $.jGrowl("#{flash[:success]}", { theme: 'success' })
7
7
  - elsif flash[:alert].present?
8
8
  javascript:
9
- $.jGrowl("#{flash[:alert].html_safe}", {theme: 'error'})
9
+ $.jGrowl("#{flash[:alert].html_safe}", { theme: 'error' })
@@ -1,4 +1,7 @@
1
- - @model.available_actions.select{|act| act if act.display_type == :modal}.each do |custom_action|
1
+ - custom_action_with_modals = @model.available_actions.select{ |act| act if act.display_type == :modal }
2
+ - if @associated_model
3
+ - custom_action_with_modals += @associated_model.available_actions.select{ |act| act if act.display_type == :modal }
4
+ - custom_action_with_modals.each do |custom_action|
2
5
  .modal.fade id="#{custom_action.name.classify}Modal" aria-hidden="true" aria-labelledby="#{custom_action.name.classify}ModalLabel" tabindex="1"
3
6
  .modal-dialog
4
7
  .modal-content
@@ -2,6 +2,7 @@ require_relative 'constants'
2
2
  require_relative 'models/action'
3
3
  require_relative 'models/importer'
4
4
  require_relative 'models/custom_action'
5
+ require_relative 'models/bulk_action'
5
6
  require_relative 'models/field'
6
7
  require_relative 'models/form_field'
7
8
  require_relative 'models/blocks'
@@ -24,7 +25,7 @@ module CmAdmin
24
25
  include Models::Blocks
25
26
  include Models::DslMethod
26
27
  attr_accessor :available_actions, :actions_set, :available_fields, :additional_permitted_fields,
27
- :current_action, :params, :filters, :available_tabs, :icon_name
28
+ :current_action, :params, :filters, :available_tabs, :icon_name, :bulk_actions
28
29
  attr_reader :name, :ar_model, :is_visible_on_sidebar, :importer
29
30
 
30
31
  def initialize(entity, &block)
@@ -33,6 +34,7 @@ module CmAdmin
33
34
  @is_visible_on_sidebar = true
34
35
  @icon_name = 'fa fa-th-large'
35
36
  @available_actions ||= []
37
+ @bulk_actions ||= []
36
38
  @additional_permitted_fields ||= []
37
39
  @current_action = nil
38
40
  @available_tabs ||= []
@@ -36,6 +36,10 @@ module CmAdmin
36
36
  self.sort_direction = :desc
37
37
  self.scopes ||= []
38
38
  self.icon_name = 'fa fa-th-large'
39
+ self.verb = :get
40
+ self.route_type = nil
41
+ self.display_type = nil
42
+
39
43
  end
40
44
 
41
45
  def set_values(page_title, page_description, partial)
@@ -45,12 +49,14 @@ module CmAdmin
45
49
  end
46
50
 
47
51
  def controller_action_name
48
- if self.action_type == :custom
52
+ if action_type == :custom
49
53
  'cm_custom_method'
50
- elsif self.parent
51
- 'cm_' + self.parent
54
+ elsif action_type == :bulk_action
55
+ 'cm_bulk_action'
56
+ elsif parent
57
+ "cm_#{parent}"
52
58
  else
53
- 'cm_' + name
59
+ "cm_#{name}"
54
60
  end
55
61
  end
56
62
 
@@ -0,0 +1,18 @@
1
+ require_relative 'actions/blocks'
2
+
3
+ module CmAdmin
4
+ module Models
5
+ class BulkAction < Action
6
+
7
+ def initialize(attributes = {}, &block)
8
+ super
9
+ override_default_values
10
+ end
11
+
12
+ def override_default_values
13
+ self.icon_name = 'fa fa-layer-group'
14
+ self.verb = :post
15
+ end
16
+ end
17
+ end
18
+ end
@@ -127,6 +127,15 @@ module CmAdmin
127
127
  # self.class.class_eval(&block)
128
128
  end
129
129
 
130
+ def bulk_action(name: nil, display_name: nil, display_if: lambda { |arg| return true }, redirection_url: nil, icon_name: nil, verb: nil, display_type: nil, route_type: nil, partial: nil, &block)
131
+ bulk_action = CmAdmin::Models::BulkAction.new(
132
+ name: name, display_name: display_name, display_if: display_if,
133
+ redirection_url: redirection_url, icon_name: icon_name, action_type: :bulk_action,
134
+ verb: verb, display_type: display_type, route_type: route_type, partial: partial, &block
135
+ )
136
+ @available_actions << bulk_action
137
+ end
138
+
130
139
  def filter(db_column_name, filter_type, options={})
131
140
  @filters << CmAdmin::Models::Filter.new(db_column_name: db_column_name, filter_type: filter_type, options: options)
132
141
  end
@@ -1,6 +1,10 @@
1
+ require_relative 'utils/helpers'
2
+
1
3
  module CmAdmin
2
4
  module Models
3
5
  class Filter
6
+ include Utils::Helpers
7
+
4
8
  attr_accessor :db_column_name, :filter_type, :placeholder, :collection
5
9
 
6
10
  VALID_FILTER_TYPES = Set[:date, :multi_select, :range, :search, :single_select].freeze
@@ -8,37 +12,55 @@ module CmAdmin
8
12
  def initialize(db_column_name:, filter_type:, options: {})
9
13
  raise TypeError, "Can't have array of multiple columns for #{filter_type} filter" if db_column_name.is_a?(Array) && db_column_name.size > 1 && !filter_type.to_sym.eql?(:search)
10
14
  raise ArgumentError, "Kindly select a valid filter type like #{VALID_FILTER_TYPES.sort.to_sentence(last_word_connector: ', or ')} instead of #{filter_type} for column #{db_column_name}" unless VALID_FILTER_TYPES.include?(filter_type.to_sym)
15
+
11
16
  @db_column_name, @filter_type = structure_data(db_column_name, filter_type)
17
+ set_default_values
12
18
  options.each do |key, value|
13
- self.send("#{key.to_s}=", value)
19
+ send("#{key}=", value)
14
20
  end
15
21
  end
16
22
 
17
23
  def structure_data(db_column_name, filter_type)
18
24
  filter_type = filter_type.is_a?(Array) ? filter_type[0].to_sym : filter_type.to_sym
19
25
 
20
- case filter_type
21
- when :search
22
- db_column_name = (Array.new << db_column_name).flatten.map{|x| x.class.eql?(Hash) ? x : x.to_sym}
23
- else
24
- db_column_name = db_column_name.is_a?(Array) ? db_column_name[0].to_sym : db_column_name.to_sym
25
- end
26
+ db_column_name = case filter_type
27
+ when :search
28
+ ([] << db_column_name).flatten.map { |x| x.instance_of?(Hash) ? x : x.to_sym }
29
+ else
30
+ db_column_name.is_a?(Array) ? db_column_name[0].to_sym : db_column_name.to_sym
31
+ end
26
32
  [db_column_name, filter_type]
27
33
  end
28
34
 
35
+ # Set default placeholder for the filter.
36
+ # Date and range filter will not have any placeholder.
37
+ # Else condition is added for fallback.
38
+ def set_default_values
39
+ placeholder = case filter_type
40
+ when :search
41
+ 'Search'
42
+ when :single_select, :multi_select
43
+ "Select/search #{humanized_field_value(db_column_name)}"
44
+ else
45
+ "Enter #{humanized_field_value(db_column_name)}"
46
+ end
47
+ self.placeholder = placeholder
48
+ end
49
+
29
50
  # Methods to filter the records based on the filter type.
30
51
  class << self
31
52
  def filtered_data(filter_params, records, filters)
32
53
  if filter_params
33
54
  filter_params.each do |scope_type, scope_value|
34
- scope_name = if scope_type.eql?('date') || scope_type.eql?('range')
35
- 'date_and_range'
36
- elsif scope_type.eql?('single_select') || scope_type.eql?('multi_select')
37
- 'dropdown'
38
- else
39
- scope_type
40
- end
41
- records = self.send("cm_#{scope_name}_filter", scope_value, records, filters) if scope_value.present?
55
+ scope_name = case scope_type
56
+ when 'date', 'range'
57
+ 'date_and_range'
58
+ when 'single_select', 'multi_select'
59
+ 'dropdown'
60
+ else
61
+ scope_type
62
+ end
63
+ records = send("cm_#{scope_name}_filter", scope_value, records, filters) if scope_value.present?
42
64
  end
43
65
  end
44
66
  records
@@ -46,15 +68,17 @@ module CmAdmin
46
68
 
47
69
  def cm_search_filter(scope_value, records, filters)
48
70
  return nil if scope_value.blank?
71
+
49
72
  table_name = records.table_name
50
- filters.select{|x| x if x.filter_type.eql?(:search)}.each do |filter|
73
+ filters.select { |x| x if x.filter_type.eql?(:search) }.each do |filter|
51
74
  query_variables = []
52
75
  filter.db_column_name.each do |col|
53
- if col.is_a?(Symbol)
76
+ case col
77
+ when Symbol
54
78
  query_variables << "#{table_name.pluralize}.#{col}"
55
- elsif col.is_a?(Hash)
79
+ when Hash
56
80
  col.map do |key, value|
57
- value.map {|val| query_variables << "#{key.to_s.pluralize}.#{val}" }
81
+ value.map { |val| query_variables << "#{key.to_s.pluralize}.#{val}" }
58
82
  end
59
83
  end
60
84
  end
@@ -62,14 +86,14 @@ module CmAdmin
62
86
  terms = terms.map { |e|
63
87
  (e.gsub('*', '%').prepend('%') + '%').gsub(/%+/, '%')
64
88
  }
65
- sql = ""
89
+ sql = ''
66
90
  query_variables.each.with_index do |column, i|
67
91
  sql.concat("#{column} ILIKE ?")
68
- sql.concat(' OR ') unless query_variables.size.eql?(i+1)
92
+ sql.concat(' OR ') unless query_variables.size.eql?(i + 1)
69
93
  end
70
94
 
71
- if filter.db_column_name.map{|x| x.is_a?(Hash)}.include?(true)
72
- associations_hash = filter.db_column_name.select{|x| x if x.is_a?(Hash)}.last
95
+ if filter.db_column_name.map { |x| x.is_a?(Hash) }.include?(true)
96
+ associations_hash = filter.db_column_name.select { |x| x if x.is_a?(Hash) }.last
73
97
  records = records.left_joins(associations_hash.keys).distinct
74
98
  end
75
99
 
@@ -85,19 +109,21 @@ module CmAdmin
85
109
 
86
110
  def cm_date_and_range_filter(scope_value, records, filters)
87
111
  return nil if scope_value.nil?
112
+
88
113
  scope_value.each do |key, value|
89
- if value.present?
90
- value = value.split(' to ')
91
- from = value[0].presence
92
- to = value[1].presence
93
- records = records.where(key => from..to)
94
- end
114
+ next unless value.present?
115
+
116
+ value = value.split(' to ')
117
+ from = value[0].presence
118
+ to = value[1].presence
119
+ records = records.where(key => from..to)
95
120
  end
96
121
  records
97
122
  end
98
123
 
99
124
  def cm_dropdown_filter(scope_value, records, filters)
100
125
  return nil if scope_value.nil?
126
+
101
127
  scope_value.each do |key, value|
102
128
  records = records.where(key => value) if value.present?
103
129
  end
@@ -1,6 +1,10 @@
1
+ require_relative 'utils/helpers'
2
+
1
3
  module CmAdmin
2
4
  module Models
3
5
  class FormField
6
+ include Utils::Helpers
7
+
4
8
  attr_accessor :field_name, :label, :header, :input_type, :collection, :disabled, :helper_method,
5
9
  :placeholder, :display_if, :html_attr, :target
6
10
 
@@ -13,9 +17,10 @@ module CmAdmin
13
17
  @field_name = field_name
14
18
  set_default_values
15
19
  attributes.each do |key, value|
16
- self.send("#{key.to_s}=", value)
20
+ send("#{key}=", value)
17
21
  end
18
- self.display_if = lambda { |arg| return true } if self.display_if.nil?
22
+ set_default_placeholder
23
+ self.display_if = lambda { |arg| return true } if display_if.nil?
19
24
  raise ArgumentError, "Kindly select a valid input type like #{VALID_INPUT_TYPES.sort.to_sentence(last_word_connector: ', or ')} instead of #{self.input_type} for form field #{field_name}" unless VALID_INPUT_TYPES.include?(self.input_type.to_sym)
20
25
  end
21
26
 
@@ -23,10 +28,20 @@ module CmAdmin
23
28
  self.disabled = false
24
29
  self.label = self.field_name.to_s.titleize
25
30
  self.input_type = :string
26
- self.placeholder = "Enter #{self.field_name.to_s.downcase.gsub('_', ' ')}"
27
31
  self.html_attr = {}
28
32
  self.target = {}
29
33
  end
34
+
35
+ def set_default_placeholder
36
+ return unless placeholder.nil?
37
+
38
+ self.placeholder = case input_type&.to_sym
39
+ when :single_select, :multi_select, :date, :date_time
40
+ "Select #{humanized_field_value(field_name)}"
41
+ else
42
+ "Enter #{humanized_field_value(field_name)}"
43
+ end
44
+ end
30
45
  end
31
46
  end
32
47
  end
@@ -0,0 +1,14 @@
1
+ module CmAdmin
2
+ module Models
3
+ module Utils
4
+ module Helpers
5
+ extend ActiveSupport::Concern
6
+
7
+ # Returns the humanized value of the field.
8
+ def humanized_field_value(name, capitalize: false)
9
+ name.to_s.humanize(capitalize: capitalize)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,3 +1,3 @@
1
1
  module CmAdmin
2
- VERSION = '1.1.6'
2
+ VERSION = '1.1.8'
3
3
  end
@@ -169,7 +169,7 @@ module CmAdmin
169
169
  else
170
170
  value_mapped_text = value
171
171
  end
172
-
172
+
173
173
  concat(content_tag(:div, class: "position-relative mr-3 #{value ? '' : 'hidden'}") do
174
174
  concat filter_chip(value_mapped_text, filter)
175
175
 
@@ -7,7 +7,7 @@ module CmAdmin
7
7
  value = cm_field.helper_method ? send(cm_field.helper_method, form_obj.object, cm_field.field_name) : form_obj.object.send(cm_field.field_name)
8
8
  is_required = form_obj.object._validators[cm_field.field_name].map(&:kind).include?(:presence)
9
9
  required_class = is_required ? 'required' : ''
10
- target_action = @model.available_actions.select{|x| x.name == cm_field.target[:action_name].to_s}.first if cm_field.target.present?
10
+ target_action = @model.available_actions.select { |x| x.name == cm_field.target[:action_name].to_s }.first if cm_field.target.present?
11
11
  send("cm_#{cm_field.input_type}_field", form_obj, cm_field, value, required_class, target_action)
12
12
  end
13
13
 
@@ -16,7 +16,7 @@ module CmAdmin
16
16
  class: "normal-input #{required_class}",
17
17
  disabled: cm_field.disabled,
18
18
  value: value,
19
- placeholder: "Enter #{cm_field.field_name.to_s.humanize.downcase}",
19
+ placeholder: cm_field.placeholder,
20
20
  data: { behaviour: 'integer-only' }
21
21
  end
22
22
 
@@ -25,7 +25,7 @@ module CmAdmin
25
25
  class: "normal-input #{required_class}",
26
26
  disabled: cm_field.disabled,
27
27
  value: value,
28
- placeholder: "Enter #{cm_field.field_name.to_s.downcase.gsub('_', ' ')}",
28
+ placeholder: cm_field.placeholder,
29
29
  data: { behaviour: 'decimal-only' }
30
30
  end
31
31
 
@@ -34,12 +34,12 @@ module CmAdmin
34
34
  class: "normal-input #{required_class}",
35
35
  disabled: cm_field.disabled,
36
36
  value: value,
37
- placeholder: "Enter #{cm_field.field_name.to_s.downcase.gsub('_', ' ')}"
37
+ placeholder: cm_field.placeholder
38
38
  end
39
39
 
40
40
  def cm_single_select_field(form_obj, cm_field, value, required_class, target_action)
41
41
  form_obj.select cm_field.field_name, options_for_select(select_collection_value(form_obj.object, cm_field), form_obj.object.send(cm_field.field_name)),
42
- { include_blank: cm_field.placeholder.to_s.presence || "Select #{cm_field.field_name.to_s.humanize(capitalize: false)}}" },
42
+ { include_blank: cm_field.placeholder },
43
43
  class: "normal-input #{required_class} select-2",
44
44
  disabled: cm_field.disabled,
45
45
  data: {
@@ -53,7 +53,7 @@ module CmAdmin
53
53
  def cm_multi_select_field(form_obj, cm_field, value, required_class, target_action)
54
54
  form_obj.select cm_field.field_name,
55
55
  options_for_select(select_collection_value(form_obj.object, cm_field), form_obj.object.send(cm_field.field_name)),
56
- { include_blank: cm_field.placeholder.to_s.presence || "Select #{cm_field.field_name.to_s.humanize(capitalize: false)}" },
56
+ { include_blank: cm_field.placeholder },
57
57
  class: "normal-input #{required_class} select-2",
58
58
  disabled: cm_field.disabled, multiple: true
59
59
  end
@@ -63,7 +63,7 @@ module CmAdmin
63
63
  class: "normal-input #{required_class}",
64
64
  disabled: cm_field.disabled,
65
65
  value: value&.strftime('%d-%m-%Y'),
66
- placeholder: "Enter #{cm_field.field_name.to_s.downcase.gsub('_', ' ')}",
66
+ placeholder: cm_field.placeholder,
67
67
  data: { behaviour: 'date-only' }
68
68
  end
69
69
 
@@ -72,20 +72,20 @@ module CmAdmin
72
72
  class: "normal-input #{required_class}",
73
73
  disabled: cm_field.disabled,
74
74
  value: value,
75
- placeholder: "Enter #{cm_field.field_name.to_s.downcase.gsub('_', ' ')}",
75
+ placeholder: cm_field.placeholder,
76
76
  data: { behaviour: 'date-time' }
77
77
  end
78
78
 
79
79
  def cm_text_field(form_obj, cm_field, value, required_class, _target_action)
80
80
  form_obj.text_area cm_field.field_name,
81
81
  class: "normal-input #{required_class}",
82
- placeholder: "Enter #{cm_field.field_name.to_s.downcase.gsub('_', ' ')}"
82
+ placeholder: cm_field.placeholder
83
83
  end
84
84
 
85
85
  def cm_rich_text_field(form_obj, cm_field, value, required_class, _target_action)
86
86
  form_obj.rich_text_area cm_field.field_name,
87
87
  class: "normal-input #{required_class}",
88
- placeholder: "Enter #{cm_field.field_name.to_s.downcase.gsub('_', ' ')}"
88
+ placeholder: cm_field.placeholder
89
89
  end
90
90
 
91
91
  def cm_single_file_upload_field(form_obj, cm_field, _value, required_class, _target_action)
@@ -114,16 +114,16 @@ module CmAdmin
114
114
  # helper_method argument will accept a method where value can be passed.
115
115
  def select_collection_value(object, cm_field)
116
116
  if cm_field.helper_method
117
- collection = send(cm_field.helper_method, object, cm_field.field_name)
117
+ send(cm_field.helper_method, object, cm_field.field_name)
118
118
  elsif cm_field.collection
119
- collection = cm_field.collection
119
+ cm_field.collection
120
120
  else
121
- collection = []
121
+ []
122
122
  end
123
123
  end
124
124
 
125
125
  def format_check_box_options(value, form_obj, cm_field, required_class, target_action)
126
- if value.class == Array
126
+ if value.instance_of?(Array)
127
127
  format_check_box_array(value, form_obj, cm_field, required_class, target_action)
128
128
  else
129
129
  form_obj.check_box cm_field.field_name,
@@ -131,7 +131,7 @@ module CmAdmin
131
131
  class: "normal-input cm-checkbox #{required_class} #{target_action.present? ? 'linked-field-request' : ''}",
132
132
  disabled: cm_field.disabled,
133
133
  data: {
134
- field_name: cm_field.field_name,
134
+ field_name: cm_field.field_name,
135
135
  target_action: target_action&.name,
136
136
  target_url: target_action&.name ? cm_admin.send("#{@model.name.underscore}_#{target_action&.name}_path") : ''
137
137
  }
@@ -169,7 +169,6 @@ module CmAdmin
169
169
  end
170
170
  end
171
171
 
172
-
173
172
  def format_radio_button_options(options, form_obj)
174
173
  content_tag :div do
175
174
  options.each do |val, key|
@@ -177,7 +176,7 @@ module CmAdmin
177
176
  end
178
177
  end
179
178
  end
180
-
179
+
181
180
  def format_radio_option(val, key, form_obj)
182
181
  content_tag :div, class: 'cm-radio-section' do
183
182
  concat format_radio_button(val, form_obj)
@@ -60,6 +60,8 @@ module CmAdmin
60
60
  if custom_action.name.present? && policy([:cm_admin, @model.name.classify.constantize]).send(:"#{custom_action.name}?")
61
61
  if custom_action.display_if.call(@ar_object)
62
62
  case custom_action.display_type
63
+ when :icon_only
64
+ custom_action_icon(custom_action, current_action_name)
63
65
  when :button
64
66
  custom_action_button(custom_action, current_action_name)
65
67
  when :modal
@@ -71,6 +73,14 @@ module CmAdmin
71
73
  end
72
74
  end
73
75
 
76
+ def custom_action_icon(custom_action, current_action_name)
77
+ button_to cm_admin.send("#{@model.name.underscore}_#{custom_action.name}_path"), method: :post, params: {selected_ids: ''} do
78
+ content_tag(:span) do
79
+ content_tag(:i, '', class: custom_action.icon_name)
80
+ end
81
+ end
82
+ end
83
+
74
84
  def custom_action_button(custom_action, current_action_name)
75
85
  if current_action_name == "index"
76
86
  button_to custom_action_title(custom_action), @model.ar_model.table_name + '/' + custom_action.path, class: 'secondary-btn ml-2', method: custom_action.verb