trestle icon indicating copy to clipboard operation
trestle copied to clipboard

Any plans for batch editing?

Open lxcodes opened this issue 7 years ago • 3 comments

Apologies if this is the wrong place, but we've actually been looking to either change off our backend framework or create our own. One of the key features we need is the ability to mass-select and edit all items to set multiple many-to-many associations.

Would this feature be something planned or that would fit in this framework?

lxcodes avatar Aug 03 '17 13:08 lxcodes

Batch actions, both built-in (i.e. delete) and custom, are definitely on the roadmap, and probably fairly close to the top of the list. There's actually a small part of it already implemented (the selectable column -- not quite enough to be useful) but something had to give in order to put out an initial release.

I'll keep this issue open for any additional comments and requests in relation to this feature.

spohlenz avatar Aug 03 '17 13:08 spohlenz

@spohlenz Awesome. I'll keep an eye out for developments. Looking good so far.

lxcodes avatar Aug 03 '17 17:08 lxcodes

A few years late, but:

add app/views/trestle/resource/_scopes.html.erb:

<%= content_tag(:dl, class: admin.scopes.classes) do %>
  <div class="d-flex">
    <div class="mr-1">
      <a class="scope dropdown-toggle  <%= 'disabled' unless admin.batch_actions.any? %>" type="button" id="batchActionsDropdown" data-toggle="dropdown" aria-expanded="false">
        Batch actions
      </a>
      <div class="dropdown-menu" aria-labelledby="batchActionsDropdown">
        <% admin.batch_actions.each do |_, action| %>
          <%= button_to action.label, admin.path("batch_#{action.name}"), form_class: "batch-action-form ",  remote: true, data: {method: :post, confirm: "Are you sure?" }, class: "dropdown-item" %>
        <% end %>
      </div>
    </div>

    <% admin.scopes.grouped.each do |group, scopes| %>
      <%= content_tag(:dt, group, class: ["scope-group", ("scope-group-empty" if group.blank?)]) if admin.scopes.grouped? %>

      <dd>
        <ul class="scope-list">
          <% scopes.each do |scope| %>
            <li>
              <%= link_to persistent_params.merge(scope: (scope unless scope.active?(params))), class: ["scope", ("active" if scope.active?(params))] do %>
                <strong><%= scope.label %></strong>
                (<%= number_with_delimiter(scope.count(admin.collection(params))) %>)
              <% end %>
            </li>
          <% end %>
        </ul>
      </dd>
    <% end %>
  </div>

<% end %>

mod trestle a bit:

class Trestle::Admin
  class << self
    def batch_actions
      @batch_actions ||= {}
    end
  end
end
class Trestle::Resource::Builder
  class BatchAction
    attr_reader :name, :options, :block
    def initialize(name, options = {}, &block)
      @name = name
      @options = options
      @block = block
    end

    def label
      @options[:label] || "#{@name}"
    end
  end
  def batch_action(name, options = {}, &block)
    admin.batch_actions[name] = BatchAction.new(name, options, &block)

    controller do
      define_method "batch_#{name}" do
        instance_exec &block
      end
    end

    routes do
      post "batch_#{name}", on: :collection
    end
  end
end

some custom js which i'm not proud of:

$("form.batch-action-form").each(function(i, form) {
      form.addEventListener('submit', function (e) {
          const idElements = $('input[name="selected[]"]:checked');
          $(form).find('input[name="ids[]"]').remove()
          idElements.each(function(_, el) {
              $(form).append(`<input type="hidden" name="ids[]" value="${el.value}" />`)
          })
          return true;
      })
  })

and in your admin file:

Trestle.resource(:appointments, model: Appointment) do
  batch_action :destroy, label: "Destroy selected?" do
    appointments = Appointment.where(id: params[:ids])
    appointments.destroy_all
    flash[:message] = "Destroyed!"
    redirect_to admin.path(:index)
  end
end

Partytray avatar Mar 30 '22 20:03 Partytray