Products

Advanced table with number filters, select filters, currency formatting, and action buttons.

Products Table

Export CSV

Loading data...

Filters

Table definition app/infotable/products_table.rb
class ProductsTable < Infotable::Base
  query do
    Product.all
  end

  column :id,
    label: "ID",
    type: :integer,
    sortable: true,
    visible: true

  column :name,
    label: "Product Name",
    type: :string,
    sortable: true,
    searchable: true,
    filterable: true,
    filter_type: :text,
    visible: true

  column :sku,
    label: "SKU",
    type: :string,
    sortable: true,
    searchable: true,
    filterable: true,
    filter_type: :text,
    visible: true,
    formatter: ->(value, record) { "<code class='px-2 py-1 font-mono text-xs bg-gray-100 rounded'>#{value}</code>".html_safe }

  column :description,
    label: "Description",
    type: :text,
    visible: true,
    formatter: ->(value, record) {
      truncated = value.to_s.truncate(80)
      "<span class='text-sm text-gray-600' title='#{value}'>#{truncated}</span>".html_safe
    }

  column :category,
    label: "Category",
    type: :string,
    sortable: true,
    filterable: true,
    filter_type: :select,
    filter_options: -> { Product.distinct.pluck(:category).compact.sort },
    visible: true,
    formatter: :badge,
    formatter_options: {
      colors: {
        "Electronics" => "blue",
        "Clothing" => "purple",
        "Home & Garden" => "green",
        "Sports & Outdoors" => "red",
        "Books" => "yellow",
        "Toys & Games" => "pink",
        "Health & Beauty" => "indigo",
        "Automotive" => "gray",
        "Food & Beverage" => "green",
        "Office Supplies" => "blue"
      }
    }

  column :manufacturer,
    label: "Manufacturer",
    type: :string,
    sortable: true,
    filterable: true,
    filter_type: :select,
    filter_options: -> { Product.distinct.pluck(:manufacturer).compact.sort },
    visible: true

  column :price,
    label: "Price",
    type: :decimal,
    sortable: true,
    filterable: true,
    filter_type: :number,
    visible: true,
    formatter: :currency,
    formatter_options: { precision: 2 }

  column :cost,
    label: "Cost",
    type: :decimal,
    sortable: true,
    filterable: true,
    filter_type: :number,
    visible: true,
    formatter: :currency,
    formatter_options: { precision: 2 }

  column :stock_quantity,
    label: "Stock",
    type: :integer,
    sortable: true,
    filterable: true,
    filter_type: :number,
    visible: true,
    formatter: ->(value, record) {
      color = if value == 0
        "red"
      elsif value < 50
        "yellow"
      else
        "green"
      end
      badge_class = case color
      when "red" then "bg-red-100 text-red-800 border-red-200"
      when "yellow" then "bg-yellow-100 text-yellow-800 border-yellow-200"
      when "green" then "bg-green-100 text-green-800 border-green-200"
      end
      "<span class='inline-flex items-center px-2.5 py-0.5 rounded-lg text-xs font-medium border #{badge_class}'>#{value}</span>".html_safe
    }

  column :rating,
    label: "Rating",
    type: :decimal,
    sortable: true,
    filterable: true,
    filter_type: :number,
    visible: true,
    formatter: ->(value, record) {
      return "-" if value.nil?
      stars = "⭐" * value.to_i
      "<span title='#{value}/5.0'>#{stars} #{number_with_precision(value, precision: 1)}</span>".html_safe
    }

  column :active,
    label: "Active",
    type: :boolean,
    sortable: true,
    filterable: true,
    filter_type: :boolean,
    visible: true,
    formatter: :boolean

  column :featured,
    label: "Featured",
    type: :boolean,
    sortable: true,
    filterable: true,
    filter_type: :boolean,
    visible: true,
    formatter: :boolean

  column :manufactured_date,
    label: "Manufactured",
    type: :date,
    sortable: true,
    filterable: true,
    filter_type: :date,
    visible: true,
    formatter: :date,
    formatter_options: { format: :short }

  column :discontinued_at,
    label: "Discontinued",
    type: :datetime,
    sortable: true,
    filterable: true,
    filter_type: :date,
    visible: true,
    formatter: ->(value, record) {
      value ? "<span class='text-sm text-red-600'>#{value.strftime('%Y-%m-%d')}</span>".html_safe : "<span class='text-gray-400'>-</span>".html_safe
    }

  column :created_at,
    label: "Created",
    type: :datetime,
    sortable: true,
    visible: false,
    formatter: :date,
    formatter_options: { format: :short }

  column :actions,
    label: "Actions",
    type: :action,
    visible: true,
    formatter: :action,
    width: "250px",
    formatter_options: {
      actions: [
        {
          label: "View",
          url: ->(record) { "/products/#{record.id}" },
          color: "primary"
        },
        {
          label: "Edit",
          url: ->(record) { "/products/#{record.id}/edit" }
        }
      ]
    }

  per_page 25
  per_page_options [ 10, 25, 50, 100, 250 ]
  infinite_scroll true
  table_min_height "500px"
  table_max_height "700px"
  default_sort :created_at, :desc
  row_size :mid
end