Add batch remove for collections in reports (#39020)

This commit is contained in:
Pia B. 2026-05-18 16:53:40 +02:00 committed by GitHub
parent 2402730083
commit 07a05e1edf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 85 additions and 15 deletions

View File

@ -20,7 +20,7 @@ module Admin
def batch
authorize [:admin, :collection], :index?
@collection_batch_action = Admin::CollectionBatchAction.new(admin_collection_batch_action_params.merge(current_account: current_account, report_id: params[:report_id], type: 'report'))
@collection_batch_action = Admin::CollectionBatchAction.new(admin_collection_batch_action_params.merge(current_account: current_account, report_id: params[:report_id], type: action_from_button))
@collection_batch_action.save!
rescue ActionController::ParameterMissing
@ -57,5 +57,13 @@ module Admin
def set_collections
@collections = @account.collections.includes(accepted_collection_items: :account).page(params[:page]).per(PER_PAGE)
end
def action_from_button
if params[:report]
'report'
elsif params[:remove_from_report]
'remove_from_report'
end
end
end
end

View File

@ -16,6 +16,8 @@ module Admin
@report_notes = @report.notes.chronological.includes(:account)
@action_logs = @report.history.includes(:target)
@form = Admin::StatusBatchAction.new
@collection_form = Admin::CollectionBatchAction.new
@collections = @report.collections
@statuses = @report.statuses.with_includes
end

View File

@ -69,8 +69,9 @@ on('change', '#batch_checkbox_all', ({ target }) => {
'.batch-table__select-all',
);
document
.querySelectorAll<HTMLInputElement>(batchCheckboxClassName)
target
.closest('.batch-table')
?.querySelectorAll<HTMLInputElement>(batchCheckboxClassName)
.forEach((content) => {
content.checked = target.checked;
});
@ -112,17 +113,20 @@ on('click', '.batch-table__select-all button', () => {
}
});
on('change', batchCheckboxClassName, () => {
const checkAllElement = document.querySelector<HTMLInputElement>(
on('change', batchCheckboxClassName, (event) => {
const targetTable = (event.target as HTMLElement).closest('.batch-table');
if (!targetTable) return;
const checkAllElement = targetTable.querySelector<HTMLInputElement>(
'input#batch_checkbox_all',
);
const selectAllMatchingElement = document.querySelector(
const selectAllMatchingElement = targetTable.querySelector(
'.batch-table__select-all',
);
if (checkAllElement) {
const allCheckboxes = Array.from(
document.querySelectorAll<HTMLInputElement>(batchCheckboxClassName),
targetTable.querySelectorAll<HTMLInputElement>(batchCheckboxClassName),
);
checkAllElement.checked = allCheckboxes.every((content) => content.checked);
checkAllElement.indeterminate =

View File

@ -13,7 +13,12 @@ class Admin::CollectionBatchAction < Admin::BaseAction
def process_action!
return unless collection_ids
add_to_report!
case type
when 'report'
add_to_report!
when 'remove_from_report'
handle_remove_from_report!
end
end
def add_to_report!
@ -24,6 +29,13 @@ class Admin::CollectionBatchAction < Admin::BaseAction
@report_id = @report.id
end
def handle_remove_from_report!
return unless with_report?
@report.collections = (@report.collections - selected_collections)
@report.save!
end
def selected_collections
@report.target_account.collections.where(id: collection_ids)
end

View File

@ -63,23 +63,26 @@
= render partial: 'admin/shared/status_batch_row', collection: @statuses, as: :status, locals: { f: f }
- if Mastodon::Feature.collections_enabled?
%details{ open: @report.collections.any? }
%details{ open: @collections.any? }
%summary
= t 'admin.reports.collections', count: @report.collections.size
= t 'admin.reports.collections', count: @collections.size
= form_with model: @form, url: batch_admin_account_collections_path(@report.target_account_id, report_id: @report.id) do |f|
= form_with model: @collection_form, url: batch_admin_account_collections_path(@report.target_account_id, report_id: @report.id) do |f|
.batch-table
.batch-table__toolbar
%label.batch-table__toolbar__select.batch-checkbox-all
= check_box_tag :batch_checkbox_all, nil, false
.batch-table__toolbar__actions
= link_to safe_join([material_symbol('add'), t('admin.reports.add_to_report')]),
admin_account_collections_path(@report.target_account_id, report_id: @report.id),
class: 'table-action-link'
- if !@collections.empty? && @report.unresolved?
= f.button safe_join([material_symbol('close'), t('admin.collections.batch.remove_from_report')]), name: :remove_from_report, class: 'table-action-link', type: :submit
.batch-table__body
- if @report.collections.empty?
- if @collections.empty?
= nothing_here 'nothing-here--under-tabs'
- else
= render partial: 'admin/shared/collection_batch_row', collection: @report.collections, as: :collection, locals: { f: f }
= render partial: 'admin/shared/collection_batch_row', collection: @collections, as: :collection, locals: { f: f }
- if @report.unresolved?
%hr.spacer/

View File

@ -349,6 +349,7 @@ en:
back_to_report: Back to report page
batch:
add_to_report: 'Add to report #%{id}'
remove_from_report: Remove from report
report: Report
collection_title: Collection by %{name}
contents: Contents

View File

@ -46,5 +46,15 @@ RSpec.describe Admin::CollectionBatchAction do
expect(Report.last.collections).to include(collection)
end
end
context 'when type is remove_from_report' do
let(:report_id) { report.id }
let(:type) { 'remove_from_report' }
it 'does not remove report but removes collection' do
expect { subject.save! }.to change { report.reload.collections }.to([])
.and not_change(Report, :count)
end
end
end
end

View File

@ -6,7 +6,8 @@ RSpec.describe 'Admin Collections' do
let(:account) { Fabricate(:account) }
let(:other_account) { Fabricate(:account) }
let(:collection) { Fabricate(:collection, account: account) }
let!(:second_collection) { Fabricate(:collection, account: account) }
let(:unreported_collection) { Fabricate(:collection, account: account) }
let(:second_collection) { Fabricate(:collection, account: account) }
let(:report) { Fabricate(:report, account: other_account, target_account: account) }
before do
@ -32,20 +33,49 @@ RSpec.describe 'Admin Collections' do
end
describe 'POST /admin/accounts/:account_id/collections/batch' do
subject { post batch_admin_account_collections_path(account_id: account.id, report_id: report_id, admin_collection_batch_action: { collection_ids: [collection.id, second_collection.id] }) }
subject { post batch_admin_account_collections_path(:account_id => account.id, :report_id => report_id, action_from_button => '', :admin_collection_batch_action => { collection_ids: [collection.id, second_collection.id] }) }
context 'with a valid report' do
let(:report_id) { report.id }
let(:action_from_button) { 'report' }
it 'redirects to the report page' do
report.collections << collection
subject
expect(response).to redirect_to(admin_report_path(report.id))
expect(response.body).to be_empty
expect(response).to have_http_status(302)
end
end
context 'with an invalid report' do
let(:report_id) { nil }
let(:action_from_button) { 'report' }
it 'redirects to the account collections page' do
subject
expect(response).to redirect_to(admin_account_collections_path(account.id))
expect(response).to have_http_status(302)
end
end
context 'with valid remove_from_report' do
let(:report_id) { report.id }
let(:action_from_button) { 'remove_from_report' }
before do
report.collections << [second_collection, unreported_collection]
end
it 'redirects to the account collections page' do
subject
expect(response).to redirect_to(admin_report_path(report.id))
end
end
context 'with invalid remove_from_report' do
let(:report_id) { nil }
let(:action_from_button) { 'remove_from_report' }
it 'redirects to the account collections page' do
subject