Module: CmAdmin::Models::DslMethod

Extended by:
ActiveSupport::Concern
Defined in:
lib/cm_admin/models/dsl_method.rb

Instance Method Summary collapse

Instance Method Details

#action_group(name, icon_name: 'fa fa-list', icon_style: nil) ⇒ Object

Create a new group for actions

Examples:

Creating a group

group 'Basic Information', icon_name: 'fa fa-list', icon_style: 'color: #000000' do
  custom_action 'Edit', verb: 'get', display_type: :button, icon_name: 'fa fa-edit', icon_style: 'color: #000000' do
    @posts = Post.all
  end
end

Parameters:

  • name (String)

    the name of group

  • icon_name (String) (defaults to: 'fa fa-list')

    the icon name of group, follow font-awesome icon name

  • icon_style (String) (defaults to: nil)

    the icon style of group, follow font-awesome icon style, example: “–fa-primary-color: #fecb3e; –fa-secondary-color: #e63b7a;”



295
296
297
298
299
# File 'lib/cm_admin/models/dsl_method.rb', line 295

def action_group(name, icon_name: 'fa fa-list', icon_style: nil)
  @current_group = { name:, icon_name:, icon_style: }
  yield
  @current_group = nil
end

#alert_box(header: nil, body: nil, type: nil, icon_name: nil, partial: nil, display_if: ->(_arg) { true }, html_attrs: {}) ⇒ Object

Note:

Alerts cannot be placed inside nested sections. If added within a nested section, the alert will appear on the wrapped cm_show_section.

Note:

Only the specified types (info, success, danger, warning) are supported. Any other type will default to a standard div.

Adds a new alert to the current section.

Examples:

Basic info alert

alert_box(header: "Information", body: "This is an informational message.", type: :info)

Basic info alert with custom body

alert_box(header: "Information", body: "This is an informational message. <br>This is a break text", type: :info)

Alert with custom partial

alert_box(partial: "/users/sessions/alert", display_if: ->(arg) { arg.present? })

Alert with conditional display and custom HTML attributes

alert_box(
  header: "Warning",
  body: "Please review your submission.",
  type: :warning,
  display_if: ->(user) { user.submissions.any?(&:incomplete?) },
  html_attrs: { id: "submission-warning", data: { turbo_frame: "warnings" } }
)

Parameters:

  • header (String, nil) (defaults to: nil)

    The title text for the alert.

  • body (String, nil) (defaults to: nil)

    A string to display as the body of the alert.

  • type (Symbol, nil) (defaults to: nil)

    The type of alert. Accepts one of the following symbols: :info, :success, :danger, :warning.

  • partial (String, nil) (defaults to: nil)

    The path to a custom partial or HTML for the alert.

  • display_if (Proc, nil) (defaults to: ->(_arg) { true })

    A lambda function that determines whether the alert should be shown. Should return a boolean.

  • html_attrs (Hash) (defaults to: {})

    Additional HTML attributes to apply to the alert. Has no effect on partials.

See Also:



531
532
533
# File 'lib/cm_admin/models/dsl_method.rb', line 531

def alert_box(header: nil, body: nil, type: nil, icon_name: nil, partial: nil, display_if: ->(_arg) { true }, html_attrs: {})
  @current_action.alerts << CmAdmin::Models::Alert.new(header:, body:, type:, icon_name:, partial:, display_if:, html_attrs:)
end

#all_db_columns(options = {}) ⇒ Object

Get all columns for a model for index layout.

Examples:

Getting all columns

all_db_columns(exclude: ['id'])

Parameters:

  • exclude (Array)

    the array of fields to exclude



274
275
276
277
278
279
280
281
282
283
# File 'lib/cm_admin/models/dsl_method.rb', line 274

def all_db_columns(options = {})
  field_names = instance_variable_get(:@ar_model)&.columns&.map { |x| x.name.to_sym }
  if options.include?(:exclude) && field_names
    excluded_fields = ([] << options[:exclude]).flatten.map(&:to_sym)
    field_names -= excluded_fields
  end
  field_names.each do |field_name|
    column field_name
  end
end

#bulk_action(name: nil, display_name: nil, display_if: ->(_) { true }, redirection_url: nil, icon_name: nil, verb: nil, display_type: nil, modal_configuration: {}, route_type: nil, partial: nil, icon_style: nil, execution_mode: :individual, success_message: ->(_arg) { nil }, error_message: ->(_arg) { nil }, alert_type: :banner, &block) ⇒ Object

Create a new bulk action for model

Examples:

Creating a bulk action

bulk_action name: 'approve', display_name: 'Approve', display_if: lambda { |arg| arg.draft? }, redirection_url: '/posts', icon_name: 'fa-regular fa-circle-check', verb: :patch, display_type: :modal, modal_configuration: { title: 'Approve Post', description: 'Are you sure you want approve this post', confirmation_text: 'Approve' }, execution_mode: :individual do
  posts = ::Post.where(id: params[:ids])
  posts.each(&:approved!)
  posts
end

Creating a bulk action with form modal

bulk_action name: 'approve', display_name: 'Approve', display_if: lambda { |arg| arg.draft? }, redirection_url: '/posts', icon_name: 'fa-regular fa-circle-check', verb: :patch, display_type: :form_modal, modal_configuration: { title: 'Approve Post', confirmation_text: 'Approve' }, execution_mode: :individual do
 form do
   cm_section 'Comment' do
     form_field :comment
   end
 end
 on_submit do |id|
   post = ::Post.find(id)
   post.approved!
   post
 end
end

Parameters:

  • name (String) (defaults to: nil)

    the name of action

  • display_name (String) (defaults to: nil)

    the display name of action

  • display_if (Proc) (defaults to: ->(_) { true })

    A lambda that takes the current object and return true or false

  • redirection_url (String) (defaults to: nil)

    the redirection url of action

  • icon_name (String) (defaults to: nil)

    the icon name of action, follow font-awesome icon name

  • verb (String) (defaults to: nil)

    the verb of action, get, post, put, patch or delete

  • display_type (Symbol) (defaults to: nil)

    the display type of action, :page, :modal, :form_modal, :button, :icon_only[deprecated]

  • modal_configuration (Hash) (defaults to: {})

    the configuration of modal

  • route_type (String) (defaults to: nil)

    the route type of action, member, collection

  • partial (String) (defaults to: nil)

    the partial path of action

  • execution_mode (Symbol) (defaults to: :individual)

    the types of execution mode are :bulk, :individual [default :individual]

  • alert_type (Symbol) (defaults to: :banner)

    the type of success alert to show. Choices are :flash and :banner. This is only for success messages.



426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
# File 'lib/cm_admin/models/dsl_method.rb', line 426

def bulk_action(name: nil, display_name: nil, display_if: ->(_) { true }, redirection_url: nil, icon_name: nil,
                verb: nil, display_type: nil, modal_configuration: {}, route_type: nil, partial: nil, icon_style: nil,
                execution_mode: :individual, success_message: ->(_arg) { nil }, error_message: ->(_arg) { nil }, alert_type: :banner, &block)
  bulk_action = CmAdmin::Models::BulkAction.new(
    name:, display_name:, display_if:, modal_configuration:,
    redirection_url:, icon_name:, action_type: :bulk_action,
    execution_mode:, verb:, display_type:, route_type:, partial:,
    icon_style:, success_message:, error_message:, alert_type:, &block
  )
  if display_type == :form_modal
    @action = bulk_action
    @current_action = @action
    @current_action.verb = :post
    @available_actions << @action
    define_singleton_method(:on_submit) do |&code_block|
      @action.code_block = code_block
    end
    yield
  else
    @available_actions << bulk_action
  end
end

#cm_edit(display_name: 'Edit', page_title: nil, page_description: nil, partial: nil, redirect_to: nil) ⇒ Object

Create a form for edit action

Create a form field for form
@param form_field [String] the name of field
@param input_type [Symbol] the type of field, +:integer+, +:decimal+, +:string+, +:single_select+, +:multi_select+, +:date+, +:date_time+, +:text+, +:switch+, +:custom_single_select+, +:checkbox_group+, +:radio_button+, +:custom_string+, +:custom_date+, +:radio_button_group+
@param is_required [Boolean] the field is required or not, or can be set automatically based on model validation
@param collection [Array] the collection of field, use with single_select or multi_select
For understanding difference between switch and check_box, refer to https://blog.uxtweak.com/checkbox-vs-toggle-switch/

Examples:

Editing page with a redirect

cm_edit(display_name: 'Edit Post', page_title: "Edit Post", page_description: 'Enter all details to edit Post', redirect_to: ->(current_object) { "/pages/#{current_object.id}" }) do
  cm_section 'Details' do
    form_field :title, input_type: :string
    form_field :body, input_type: :rich_text
  end
end

Parameters:

  • display_name (String) (defaults to: 'Edit')

    the display/button name of page

  • page_title (String) (defaults to: nil)

    or [Symbol] the title of page, if symbol passed, it will be a method name on model

  • page_description (String) (defaults to: nil)

    the description of page

  • partial (String) (defaults to: nil)

    the partial path of page

  • redirect_to (Proc, nil) (defaults to: nil)

    A lambda that takes the current object and redirect to path after update



74
75
76
77
78
79
# File 'lib/cm_admin/models/dsl_method.rb', line 74

def cm_edit(display_name: 'Edit', page_title: nil, page_description: nil, partial: nil, redirect_to: nil)
  @current_action = CmAdmin::Models::Action.find_by(self, name: 'edit')
  page_title ||= "Edit #{ar_model.model_name.plural.titleize}"
  @current_action.set_values(display_name, page_title, page_description, partial, redirect_to)
  yield
end

#cm_index(display_name: nil, page_title: nil, page_description: nil, partial: nil, view_type: :table) ⇒ Object

Create a table for index page with pagination.

Examples:

Index page

cm_index do
  page_title 'Post'
  column :title
  column :created_at, field_type: :date, format: '%d %b, %Y'
  column :updated_at, field_type: :date, format: '%d %b, %Y', header: 'Last Updated At'
end

Parameters:

  • display_name (String) (defaults to: nil)

    the display name of page

  • page_title (String) (defaults to: nil)

    the title of page

  • page_description (String) (defaults to: nil)

    the description of page

  • partial (String) (defaults to: nil)

    the partial path of page

  • view_type (Symbol) (defaults to: :table)

    view type of page :table, :card or :kanban



21
22
23
24
25
26
# File 'lib/cm_admin/models/dsl_method.rb', line 21

def cm_index(display_name: nil, page_title: nil, page_description: nil, partial: nil, view_type: :table)
  @current_action = CmAdmin::Models::Action.find_by(self, name: 'index')
  page_title ||= ar_model.model_name.plural.titleize
  @current_action.set_values(display_name, page_title, page_description, partial, view_type)
  yield
end

#cm_new(display_name: 'Add', page_title: nil, page_description: nil, partial: nil, redirect_to: nil, allow_create_action: -> { true }) ⇒ Object

Create a form for new action

Create a form field for form
@param form_field [String] the name of field
@param input_type [Symbol] the type of field, +:integer+, +:decimal+, +:string+, +:single_select+, +:multi_select+, +:date+, +:date_time+, +:text+, +:switch+, +:custom_single_select+, +:checkbox_group+, +:radio_button+, +:custom_string+, +:custom_date+, +:radio_button_group+
@param is_required [Boolean] the field is required or not, or can be set automatically based on model validation
@param collection [Array] the collection of field, use with single_select or multi_select
For understanding difference between switch and check_box, refer to https://blog.uxtweak.com/checkbox-vs-toggle-switch/

Examples:

Creating a new page with a redirect

cm_new(display_name: 'Add Post', page_title: "Add Post", page_description: 'Enter all details to add Post', redirect_to: ->(current_object) { "/pages/#{current_object.id}" }) do
  cm_section 'Details' do
    form_field :title, input_type: :string
    form_field :body, input_type: :rich_text
  end
end

Parameters:

  • display_name (String) (defaults to: 'Add')

    the display/button name of page

  • page_title (String) (defaults to: nil)

    the title of page

  • page_description (String) (defaults to: nil)

    the description of page

  • partial (String) (defaults to: nil)

    the partial path of page

  • redirect_to (Proc, nil) (defaults to: nil)

    A lambda that takes the current object and redirect to path after create

  • allow_create_action (Proc) (defaults to: -> { true })

    A lambda that determines if the Add button (create/new action) should be shown



103
104
105
106
107
108
109
# File 'lib/cm_admin/models/dsl_method.rb', line 103

def cm_new(display_name: 'Add', page_title: nil, page_description: nil, partial: nil, redirect_to: nil, allow_create_action: -> { true })
  @current_action = CmAdmin::Models::Action.find_by(self, name: 'new')
  page_title ||= "Add #{ar_model.model_name.plural.titleize}"
  @current_action.set_values(display_name, page_title, page_description, partial, redirect_to)
  @current_action.allow_create_action = allow_create_action
  yield
end

#cm_section(section_name, display_if: nil, col_size: nil, html_attrs: nil, partial: nil, &block) ⇒ Object

Examples:

Creating a section

cm_section('Basic Information', display_if: ->(current_object) { current_object.name == 'John' }, col_size: 6, html_attrs: { class: 'section-class' }) do
  field :title, input_type: :string
end


207
208
209
210
211
# File 'lib/cm_admin/models/dsl_method.rb', line 207

def cm_section(section_name, display_if: nil, col_size: nil, html_attrs: nil, partial: nil, &block)
  @available_fields[@current_action.name.to_sym] ||= []
  @available_fields[@current_action.name.to_sym] << CmAdmin::Models::Section.new(section_name, @current_action, @model, display_if, html_attrs,
                                                                                 col_size, partial, &block)
end

#cm_show(display_name: nil, page_title: nil, page_description: nil, partial: nil) ⇒ Object

Create a view for show page

Examples:

Showing page

cm_show page_title: :title do
  tab :profile, '' do
    cm_section 'Post Details' do
      field :title
      field :body, field_type: :rich_text
      field :is_featured
      field :status, field_type: :tag, tag_class: STATUS_TAG_COLOR
    end
  end
end

Parameters:

  • display_name (String) (defaults to: nil)

    the display name of page

  • page_title (String | Symbol) (defaults to: nil)

    the title of page, if symbol passed, it will be a method name on model

  • page_description (String) (defaults to: nil)

    the description of page

  • partial (String) (defaults to: nil)

    the partial path of page



46
47
48
49
50
51
# File 'lib/cm_admin/models/dsl_method.rb', line 46

def cm_show(display_name: nil, page_title: nil, page_description: nil, partial: nil)
  @current_action = CmAdmin::Models::Action.find_by(self, name: 'show')
  page_title ||= ar_model.model_name.plural.titleize
  @current_action.set_values(display_name, page_title, page_description, partial)
  yield
end

#cm_show_section(section_name, display_if: nil, html_attrs: nil, partial: nil, &block) ⇒ Object

Deprecated.

Use #cm_section instead of this method



214
215
216
# File 'lib/cm_admin/models/dsl_method.rb', line 214

def cm_show_section(section_name, display_if: nil, html_attrs: nil, partial: nil, &block)
  cm_section(section_name, display_if:, html_attrs:, partial:, &block)
end

#column(field_name, options = {}) ⇒ Object

Create a new column on index layout.

Examples:

Creating a column

column('name', field_type: :string)

Parameters:

  • field_name (String)

    the name of field

  • field_type (Symbol)

    the type of field, :string, :text, :image, :date, :rich_text, :time, :integer, :decimal, :custom, :datetime, :money, :money_with_symbol, :link, :association, :enum, :tag, :attachment, :drawer

  • header (String)

    the header of field

  • format (String)

    the format of field for date field

  • helper_method (Symbol)

    the helper method for field, should be defined in custom_helper.rb file, will take two arguments, record and field_name

  • export_method (Symbol)

    the export method for field, should be defined in model, will take no arguments

  • height (Integer)

    the height of field for image field

  • width (Integer)

    the width of field for image field



233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/cm_admin/models/dsl_method.rb', line 233

def column(field_name, options = {})
  return unless @current_action.instance_of?(CmAdmin::Models::Action)

  @available_fields[@current_action.name.to_sym] ||= []
  if @available_fields[@current_action.name.to_sym].select(&:lockable).size.positive? && options[:lockable]
    raise 'Only one column can be locked in a table.'
  end

  if @available_fields[@current_action.name.to_sym].select(&:kanban_image).size.positive? && options[:kanban_image]
    raise 'Only one column can be kanban image in a card view.'
  end

  if @available_fields[@current_action.name.to_sym].select(&:kanban_footer).size >= 2 && options[:kanban_footer]
    raise 'Only two columns can be kanban footer in a card view.'
  end

  duplicate_columns = @available_fields[@current_action.name.to_sym].filter { |x| x.field_name.to_sym == field_name }
  terminate = false

  if duplicate_columns.size.positive?
    duplicate_columns.each do |column|
      if options[:field_type].to_s != 'association'
        terminate = true
      elsif options[:field_type].to_s == 'association' && column.association_name.to_s == options[:association_name].to_s
        terminate = true
      end
    end
  end

  return if terminate

  add_to_filter = options[:add_to_filter].nil? || options[:add_to_filter]
  generate_filter_for_columns(field_name, add_to_filter: add_to_filter)

  @available_fields[@current_action.name.to_sym] << CmAdmin::Models::Column.new(field_name, options)
end

#custom_action(name: nil, page_title: nil, page_description: nil, display_name: nil, verb: nil, layout: nil, layout_type: nil, partial: nil, path: nil, display_type: nil, redirect_to: nil, modal_configuration: {}, url_params: {}, display_if: ->(_) { true }, route_type: nil, icon_name: 'fa fa-th-large', icon_style: nil, group_name: nil, success_message: ->(_) { nil }, error_message: ->(_, _) { nil }, alert_type: :flash, &block) ⇒ Object

Create a new custom action for model custom_action name: ‘change_password’, route_type: ‘member’, verb: ‘get’, icon_name: ‘fa-solid fa-key’, page_title: ‘Change Password’, path: ‘:id/change_password’, display_type: :form_modal do

form do
  cm_section 'Password Details' do
    form_field :username
    form_field :age_group_id, input_type: :single_select, helper_method: :age_group_type_collection
    form_field :cultural_background_ids, input_type: :multi_select, helper_method: :cultural_background_type_collection
    form_field :language, input_type: :single_select, helper_method: :language_collection
  end
end
on_submit do
  @customer = ::Customer.find(params[:id])
  @customer.update!(gender_id: params[:customer][:age_group_id])
  @customer
end

end Note: The form block is mandatory for form modal and form page. Params fields will always be under the parent class, for example: params[:age_group_id]

Examples:

Creating a custom action with modal

custom_action name: 'approve', route_type: 'member', verb: 'patch', icon_name: 'fa-regular fa-circle-check', path: ':id/approve', display_type: :modal, display_if: lambda(&:draft?), modal_configuration: { title: 'Approve Post', description: 'Are you sure you want approve this post', confirmation_text: 'Approve' } do
  post = ::Post.find(params[:id])
  post.approved!
  post
end

Creating a custom action with button

custom_action name: 'approve', route_type: 'member', verb: 'patch', icon_name: 'fa-regular fa-circle-check', path: ':id/approve', display_type: :button, display_if: lambda(&:draft?), group_name: 'my action' do
  post = ::Post.find(params[:id])
  post.approved!
  post
end

Creating a custom action with form modal and form page

Parameters:

  • name (String) (defaults to: nil)

    the name of action

  • page_title (String) (defaults to: nil)

    the title of page

  • page_description (String) (defaults to: nil)

    the description of page

  • display_name (String) (defaults to: nil)

    the display name of action

  • verb (String) (defaults to: nil)

    the verb of action, get, post, put, patch or delete

  • layout (String) (defaults to: nil)

    the layout of action

  • layout_type (String) (defaults to: nil)

    the layout type of action, cm_association_index, cm_association_show

  • partial (String) (defaults to: nil)

    the partial path of action

  • path (String) (defaults to: nil)

    the path of action

  • display_type (Symbol) (defaults to: nil)

    the display type of action, :button, :modal , :form_modal, :form_page, :page, :icon_only

  • modal_configuration (Hash) (defaults to: {})

    the configuration of modal

  • url_params (Hash) (defaults to: {})

    the url params of action

  • display_if (Proc) (defaults to: ->(_) { true })

    A lambda that takes the current object and return true or false

  • route_type (String) (defaults to: nil)

    the route type of action, member, collection

  • icon_name (String) (defaults to: 'fa fa-th-large')

    the icon name of action, follow font-awesome icon name

  • icon_style (String) (defaults to: nil)

    the icon style of action, follow font-awesome icon style, example: “–fa-primary-color: #fecb3e; –fa-secondary-color: #e63b7a;”

  • group_name (String) (defaults to: nil)

    the group name of action, all the action with same group name will be grouped together in dropdown.

  • alert_type (Symbol) (defaults to: :flash)

    the type of success alert to show. Choices are :flash and :banner. This is only for success messages.



353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
# File 'lib/cm_admin/models/dsl_method.rb', line 353

def custom_action(name: nil, page_title: nil, page_description: nil, display_name: nil, verb: nil, layout: nil,
                  layout_type: nil, partial: nil, path: nil, display_type: nil, redirect_to: nil,
                  modal_configuration: {}, url_params: {}, display_if: ->(_) { true }, route_type: nil,
                  icon_name: 'fa fa-th-large', icon_style: nil, group_name: nil, success_message: ->(_) { nil },
                  error_message: ->(_, _) { nil }, alert_type: :flash, &block)
  @action = CmAdmin::Models::CustomAction.new(
    page_title:, page_description:,
    name:, display_name:, verb:, layout:,
    layout_type:, partial:, path:,
    parent: current_action.name, display_type:, display_if:,
    redirect_to:, action_type: :custom, route_type:,
    icon_name:, icon_style:, modal_configuration:,
    model_name: self.name, url_params:, group_name:, alert_type:,
    success_message:, error_message:, &block
  )

  if @current_group
    @action.group_name = @current_group[:name]
    @action.group_icon_name = @current_group[:icon_name]
    @action.group_icon_style = @current_group[:icon_style]
  end

  if %i[form_page form_modal].include?(display_type)
    @current_action = @action
    @available_actions << @action

    define_singleton_method(:on_submit) do |&code_block|
      if display_type == :form_modal
        @action.code_block = code_block
      else
        @action.verb = :get
        generate_update_action(name, path, verb, redirect_to, route_type, success_message, error_message, &code_block)
      end
    end

    yield
  else
    @available_actions << @action
  end
end

#eager_load_associations(associations = []) ⇒ Object

Configure Eager load associations for action This will help us avoid N+1 queries

Examples:

Eager load associations

eager_load_assocations [:association_name]
eager_load_assocations [:constant]


594
595
596
# File 'lib/cm_admin/models/dsl_method.rb', line 594

def eager_load_associations(associations = [])
  @current_action.eager_load_associations = associations if @current_action
end

#filter(db_column_name, filter_type = nil, options = {}) ⇒ Object

Create a new filter for model

Examples:

Creating a filter

filter('name', :search)
filter('created_at', :date)
filter('status', :single_select, collection: ['draft', 'published'])
filter('status', :multi_select,  helper_method: 'status_collection')
filter('age', :range)

Creating a filter with default value lambda

filter('status', :single_select, collection: ['draft', 'published'], default_value: -> { 'draft' })
filter('category', :multi_select, collection: ['A', 'B', 'C'], default_value: -> { ['A', 'B'] })
filter('created_at', :date, default_value: -> { "#{30.days.ago.to_date} to #{Date.today}" })
filter('user_id', :single_select, helper_method: 'user_collection', default_value: -> { Current.user.id })

Parameters:

  • db_column_name (String)

    the name of column

  • filter_type (String) (defaults to: nil)

    the type of filter, :date, :multi_select, :range, :search, :single_select

  • placeholder (String)

    the placeholder of filter

  • helper_method (String)

    the helper method for filter, should be defined in custom_helper.rb file

  • filter_with (Symbol)

    filter with scope name on model

  • active_by_default (Boolean)

    make filter active by default

  • collection (Array)

    the collection of filter, use with single_select or multi_select

  • default_value (Proc)

    the default value lambda for the filter when no filter params are provided



469
470
471
472
# File 'lib/cm_admin/models/dsl_method.rb', line 469

def filter(db_column_name, filter_type = nil, options = {})
  filter_type = default_filter_type(db_column_name, filter_type)
  @filters << CmAdmin::Models::Filter.new(db_column_name:, filter_type:, options:)
end

#kanban_view(column_name, exclude: [], only: []) ⇒ Object

Set kanban view for current action

Parameters:

  • column_name (String)

    the name of column

  • exclude (Array) (defaults to: [])

    the array of fields to exclude

  • only (Array) (defaults to: [])

    the array of fields to include



131
132
133
134
135
136
137
# File 'lib/cm_admin/models/dsl_method.rb', line 131

def kanban_view(column_name, exclude: [], only: [])
  return unless @current_action

  @current_action.kanban_attr[:column_name] = column_name
  @current_action.kanban_attr[:exclude] = exclude
  @current_action.kanban_attr[:only] = only
end

#page_description(description) ⇒ Object

Set page description for current action

Parameters:

  • description (String)

    the description of page



121
122
123
124
125
# File 'lib/cm_admin/models/dsl_method.rb', line 121

def page_description(description)
  return unless @current_action

  @current_action.page_description = description
end

#page_title(title) ⇒ Object

Set page title for current action

Parameters:

  • title (String)

    the title of page



113
114
115
116
117
# File 'lib/cm_admin/models/dsl_method.rb', line 113

def page_title(title)
  return unless @current_action

  @current_action.page_title = title
end

#row(display_if: nil, html_attrs: nil, &block) ⇒ Object

Create a new row on page or form.

Examples:

Creating a row

row(display_if: ->(current_object) { current_object.name == 'John' }, html_attrs: { class: 'row-class' }) do
  cm_section 'Details' do
    form_field :title, input_type: :string
  end
end

Parameters:

  • display_if (Proc) (defaults to: nil)

    A lambda that takes the current object and return true or false

  • html_attrs (Hash) (defaults to: nil)

    A hash that contains html attributes



192
193
194
195
# File 'lib/cm_admin/models/dsl_method.rb', line 192

def row(display_if: nil, html_attrs: nil, &block)
  @available_fields[@current_action.name.to_sym] ||= []
  @available_fields[@current_action.name.to_sym] << CmAdmin::Models::Row.new(@current_action, @model, display_if, html_attrs, &block)
end

#scope_list(scopes = []) ⇒ Object

Set scopes for current action

Parameters:

  • scopes (Array) (defaults to: [])

    the array of scopes



141
142
143
144
145
# File 'lib/cm_admin/models/dsl_method.rb', line 141

def scope_list(scopes = [])
  return unless @current_action

  @current_action.scopes = scopes
end

#sort_column(column = :created_at) ⇒ Object

@deprecated: use #sortable_columns instead of this method Set sort column for filters

Examples:

Setting sort column

sort_column(:created_at)

Parameters:

  • column (Symbol) (defaults to: :created_at)

    the column name



493
494
495
# File 'lib/cm_admin/models/dsl_method.rb', line 493

def sort_column(column = :created_at)
  @current_action.sort_column = column.to_sym if @current_action
end

#sort_direction(direction = :desc) ⇒ Object

@deprecated: use #sortable_columns instead of this method Set sort direction for filters

Examples:

Setting sort direction

sort_direction(:asc)

Parameters:

  • direction (Symbol) (defaults to: :desc)

    the direction of sort, :asc, :desc



479
480
481
482
483
484
485
486
# File 'lib/cm_admin/models/dsl_method.rb', line 479

def sort_direction(direction = :desc)
  unless CmAdmin::Models::Action::VALID_SORT_DIRECTION.include?(direction.to_sym.downcase)
    raise ArgumentError,
          "Select a valid sort direction like #{CmAdmin::Models::Action::VALID_SORT_DIRECTION.join(' or ')} instead of #{direction}"
  end

  @current_action.sort_direction = direction.to_sym if @current_action
end

#sortable_columns(columns) ⇒ Object

Note:

default sort direction will be ascending

Configure sortable columns for model verified_at is a JSONB column, so we need to specify the sort_datatype

sortable_columns([{column: 'id', display_name: 'ID', default: true, default_direction: 'desc'},
                  {column: 'updated_at', display_name: 'Last Updated At'},
                  {column: 'verified_at', display_name: 'Verified At', sort_datatype: 'TIMESTAMP'}])

Examples:

Sortable Columns

sortable_columns([{column: 'id', display_name: 'ID'},
                  {column: 'updated_at', display_name: 'Last Updated At'}])

Sortable Columns with default column and direction

Sortable Columns with display_if condition

sortable_columns([{column: 'id', display_name: 'ID'},
                  {column: 'created_at', display_name: 'Created At', display_if: ->(obj) { current_user.admin? }}])

Sortable Columns with custom sort logic

sortable_columns([{column: 'request_due_date', display_name: 'Request Due Date',
                   sort_with: :sort_by_due_date_nulls_first}])
# In your model, define the scope:
# scope :sort_by_due_date_nulls_first, ->(direction) {
#   order(Arel.sql("request_due_date #{direction} NULLS FIRST"))
# }

Parameters:

  • columns (Array)

    the array of hash for column and display name

Options Hash (columns):

  • :column (String)

    the database column name

  • :display_name (String)

    the display name for the sort option

  • :default (Boolean)

    whether this is the default sort column

  • :default_direction (String) — default: 'asc'

    default sort direction (‘asc’ or ‘desc’)

  • :sort_datatype (String)

    the SQL datatype for JSONB columns (e.g., ‘TIMESTAMP’, ‘INTEGER’)

  • :sort_with (Symbol)

    custom scope method name on the model for custom sorting logic

  • :display_if (Proc)

    condition to display this sort option

Raises:

  • (ArgumentError)


567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
# File 'lib/cm_admin/models/dsl_method.rb', line 567

def sortable_columns(columns)
  @sort_columns = columns.map do |column|
    column[:display_if] ||= ->(_arg) { true }
    column
  end
  default_column = @sort_columns.filter do |column|
    column.key?(:default) || column.key?(:default_direction)
  end
  raise ArgumentError, 'only one column can be default' if default_column.size > 1

  if default_column.blank?
    @default_sort_column = nil
    @default_sort_direction = 'asc'
    return
  end
  default_column = default_column.first
  @default_sort_column = default_column[:column]
  @default_sort_direction = default_column[:default_direction] if default_column[:default_direction].present?
end

#tab(tab_name, action_name, associated_model: nil, layout_type: nil, layout: nil, partial: nil, display_if: nil, show_count: true, view_type: nil, associated_model_name: nil, allow_create_action: -> { true }, &block) ⇒ Object

Create a new tab on show page.

Examples:

Creating a tab

tab :comments, 'comment', associated_model: 'comments', layout_type: 'cm_association_index', show_count: true do
  column :message
end

Parameters:

  • tab_name (String)

    or [Symbol] the name of tab

  • action_name (String)

    the name of action

  • associated_model (String) (defaults to: nil)

    the name of associated model

  • layout_type (String) (defaults to: nil)

    the layout type of tab, cm_association_index, cm_association_show

  • layout (String) (defaults to: nil)

    the layout of tab

  • partial (String) (defaults to: nil)

    the partial path of tab

  • display_if (Proc) (defaults to: nil)

    A lambda that takes the current object and return true or false

  • view_type (Symbol) (defaults to: nil)

    view type of page :table or :card

  • show_count (Boolean) (defaults to: true)

    show count of records in tab, default is true

  • associated_model_name (String) (defaults to: nil)

    the name of associated model, if not provided, it will be the child_records class name



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/cm_admin/models/dsl_method.rb', line 164

def tab(tab_name, action_name, associated_model: nil, layout_type: nil, layout: nil, partial: nil,
        display_if: nil, show_count: true, view_type: nil, associated_model_name: nil,
        allow_create_action: -> { true }, &block)
  action_name = action_name.to_s.gsub(' ', '').underscore
  if action_name.to_s == ''
    @current_action = CmAdmin::Models::Action.find_by(self, name: 'show')
    @available_tabs << CmAdmin::Models::Tab.new(tab_name, '', display_if, show_count, &block)
  else
    action = CmAdmin::Models::Action.new(name: action_name.to_s, verb: :get, path: ":id/#{action_name}",
                                         layout_type:, layout:, partial:, child_records: associated_model,
                                         action_type: :tab, display_type: :page, model_name: name, view_type:,
                                         associated_model_name:, allow_create_action:)
    @available_actions << action
    @current_action = action
    @available_tabs << CmAdmin::Models::Tab.new(tab_name, action_name, display_if, show_count, &block)
  end
  yield if block
end