Add ability to select all accounts matching search for batch actions (#19053)
This commit is contained in:
parent
d696f729f1
commit
5b0e8cc92b
7 changed files with 138 additions and 4 deletions
|
@ -16,7 +16,11 @@ module Admin
|
||||||
def batch
|
def batch
|
||||||
authorize :account, :index?
|
authorize :account, :index?
|
||||||
|
|
||||||
@form = Form::AccountBatch.new(form_account_batch_params.merge(current_account: current_account, action: action_from_button))
|
@form = Form::AccountBatch.new(form_account_batch_params)
|
||||||
|
@form.current_account = current_account
|
||||||
|
@form.action = action_from_button
|
||||||
|
@form.select_all_matching = params[:select_all_matching]
|
||||||
|
@form.query = filtered_accounts
|
||||||
@form.save
|
@form.save
|
||||||
rescue ActionController::ParameterMissing
|
rescue ActionController::ParameterMissing
|
||||||
flash[:alert] = I18n.t('admin.accounts.no_account_selected')
|
flash[:alert] = I18n.t('admin.accounts.no_account_selected')
|
||||||
|
|
|
@ -4,18 +4,71 @@ import ready from '../mastodon/ready';
|
||||||
|
|
||||||
const batchCheckboxClassName = '.batch-checkbox input[type="checkbox"]';
|
const batchCheckboxClassName = '.batch-checkbox input[type="checkbox"]';
|
||||||
|
|
||||||
|
const showSelectAll = () => {
|
||||||
|
const selectAllMatchingElement = document.querySelector('.batch-table__select-all');
|
||||||
|
selectAllMatchingElement.classList.add('active');
|
||||||
|
};
|
||||||
|
|
||||||
|
const hideSelectAll = () => {
|
||||||
|
const selectAllMatchingElement = document.querySelector('.batch-table__select-all');
|
||||||
|
const hiddenField = document.querySelector('#select_all_matching');
|
||||||
|
const selectedMsg = document.querySelector('.batch-table__select-all .selected');
|
||||||
|
const notSelectedMsg = document.querySelector('.batch-table__select-all .not-selected');
|
||||||
|
|
||||||
|
selectAllMatchingElement.classList.remove('active');
|
||||||
|
selectedMsg.classList.remove('active');
|
||||||
|
notSelectedMsg.classList.add('active');
|
||||||
|
hiddenField.value = '0';
|
||||||
|
};
|
||||||
|
|
||||||
delegate(document, '#batch_checkbox_all', 'change', ({ target }) => {
|
delegate(document, '#batch_checkbox_all', 'change', ({ target }) => {
|
||||||
|
const selectAllMatchingElement = document.querySelector('.batch-table__select-all');
|
||||||
|
|
||||||
[].forEach.call(document.querySelectorAll(batchCheckboxClassName), (content) => {
|
[].forEach.call(document.querySelectorAll(batchCheckboxClassName), (content) => {
|
||||||
content.checked = target.checked;
|
content.checked = target.checked;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (selectAllMatchingElement) {
|
||||||
|
if (target.checked) {
|
||||||
|
showSelectAll();
|
||||||
|
} else {
|
||||||
|
hideSelectAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
delegate(document, '.batch-table__select-all button', 'click', () => {
|
||||||
|
const hiddenField = document.querySelector('#select_all_matching');
|
||||||
|
const active = hiddenField.value === '1';
|
||||||
|
const selectedMsg = document.querySelector('.batch-table__select-all .selected');
|
||||||
|
const notSelectedMsg = document.querySelector('.batch-table__select-all .not-selected');
|
||||||
|
|
||||||
|
if (active) {
|
||||||
|
hiddenField.value = '0';
|
||||||
|
selectedMsg.classList.remove('active');
|
||||||
|
notSelectedMsg.classList.add('active');
|
||||||
|
} else {
|
||||||
|
hiddenField.value = '1';
|
||||||
|
notSelectedMsg.classList.remove('active');
|
||||||
|
selectedMsg.classList.add('active');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
delegate(document, batchCheckboxClassName, 'change', () => {
|
delegate(document, batchCheckboxClassName, 'change', () => {
|
||||||
const checkAllElement = document.querySelector('#batch_checkbox_all');
|
const checkAllElement = document.querySelector('#batch_checkbox_all');
|
||||||
|
const selectAllMatchingElement = document.querySelector('.batch-table__select-all');
|
||||||
|
|
||||||
if (checkAllElement) {
|
if (checkAllElement) {
|
||||||
checkAllElement.checked = [].every.call(document.querySelectorAll(batchCheckboxClassName), (content) => content.checked);
|
checkAllElement.checked = [].every.call(document.querySelectorAll(batchCheckboxClassName), (content) => content.checked);
|
||||||
checkAllElement.indeterminate = !checkAllElement.checked && [].some.call(document.querySelectorAll(batchCheckboxClassName), (content) => content.checked);
|
checkAllElement.indeterminate = !checkAllElement.checked && [].some.call(document.querySelectorAll(batchCheckboxClassName), (content) => content.checked);
|
||||||
|
|
||||||
|
if (selectAllMatchingElement) {
|
||||||
|
if (checkAllElement.checked) {
|
||||||
|
showSelectAll();
|
||||||
|
} else {
|
||||||
|
hideSelectAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -190,6 +190,55 @@ a.table-action-link {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__select-all {
|
||||||
|
background: $ui-base-color;
|
||||||
|
height: 47px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border: 1px solid darken($ui-base-color, 8%);
|
||||||
|
border-top: 0;
|
||||||
|
color: $secondary-text-color;
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected,
|
||||||
|
.not-selected {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
padding: 8px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
|
font: inherit;
|
||||||
|
color: $highlight-text-color;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 8px;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus,
|
||||||
|
&:active {
|
||||||
|
background: lighten($ui-base-color, 8%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&__form {
|
&__form {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
border: 1px solid darken($ui-base-color, 8%);
|
border: 1px solid darken($ui-base-color, 8%);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#
|
#
|
||||||
# id :bigint(8) not null, primary key
|
# id :bigint(8) not null, primary key
|
||||||
# custom_filter_id :bigint(8) not null
|
# custom_filter_id :bigint(8) not null
|
||||||
# status_id :bigint(8) default(""), not null
|
# status_id :bigint(8) not null
|
||||||
# created_at :datetime not null
|
# created_at :datetime not null
|
||||||
# updated_at :datetime not null
|
# updated_at :datetime not null
|
||||||
#
|
#
|
||||||
|
|
|
@ -6,7 +6,8 @@ class Form::AccountBatch
|
||||||
include AccountableConcern
|
include AccountableConcern
|
||||||
include Payloadable
|
include Payloadable
|
||||||
|
|
||||||
attr_accessor :account_ids, :action, :current_account
|
attr_accessor :account_ids, :action, :current_account,
|
||||||
|
:select_all_matching, :query
|
||||||
|
|
||||||
def save
|
def save
|
||||||
case action
|
case action
|
||||||
|
@ -60,8 +61,12 @@ class Form::AccountBatch
|
||||||
end
|
end
|
||||||
|
|
||||||
def accounts
|
def accounts
|
||||||
|
if select_all_matching?
|
||||||
|
query
|
||||||
|
else
|
||||||
Account.where(id: account_ids)
|
Account.where(id: account_ids)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def approve!
|
def approve!
|
||||||
accounts.includes(:user).find_each do |account|
|
accounts.includes(:user).find_each do |account|
|
||||||
|
@ -118,4 +123,8 @@ class Form::AccountBatch
|
||||||
log_action(:approve, account.user)
|
log_action(:approve, account.user)
|
||||||
account.user.approve!
|
account.user.approve!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def select_all_matching?
|
||||||
|
select_all_matching == '1'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
|
|
||||||
= form_for(@form, url: batch_admin_accounts_path) do |f|
|
= form_for(@form, url: batch_admin_accounts_path) do |f|
|
||||||
= hidden_field_tag :page, params[:page] || 1
|
= hidden_field_tag :page, params[:page] || 1
|
||||||
|
= hidden_field_tag :select_all_matching, '0'
|
||||||
|
|
||||||
- AccountFilter::KEYS.each do |key|
|
- AccountFilter::KEYS.each do |key|
|
||||||
= hidden_field_tag key, params[key] if params[key].present?
|
= hidden_field_tag key, params[key] if params[key].present?
|
||||||
|
@ -52,6 +53,14 @@
|
||||||
= f.button safe_join([fa_icon('times'), t('admin.accounts.reject')]), name: :reject, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
|
= f.button safe_join([fa_icon('times'), t('admin.accounts.reject')]), name: :reject, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
|
||||||
|
|
||||||
= f.button safe_join([fa_icon('lock'), t('admin.accounts.perform_full_suspension')]), name: :suspend, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
|
= f.button safe_join([fa_icon('lock'), t('admin.accounts.perform_full_suspension')]), name: :suspend, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
|
||||||
|
- if true || @accounts.total_count > @accounts.size
|
||||||
|
.batch-table__select-all
|
||||||
|
.not-selected.active
|
||||||
|
%span= t('generic.all_items_on_page_selected_html', count: @accounts.size)
|
||||||
|
%button{ type: 'button' }= t('generic.select_all_matching_items', count: @accounts.total_count)
|
||||||
|
.selected
|
||||||
|
%span= t('generic.all_matching_items_selected_html', count: @accounts.total_count)
|
||||||
|
%button{ type: 'button' }= t('generic.deselect')
|
||||||
.batch-table__body
|
.batch-table__body
|
||||||
- if @accounts.empty?
|
- if @accounts.empty?
|
||||||
= nothing_here 'nothing-here--under-tabs'
|
= nothing_here 'nothing-here--under-tabs'
|
||||||
|
|
|
@ -1227,12 +1227,22 @@ en:
|
||||||
trending_now: Trending now
|
trending_now: Trending now
|
||||||
generic:
|
generic:
|
||||||
all: All
|
all: All
|
||||||
|
all_items_on_page_selected_html:
|
||||||
|
one: "<strong>%{count}</strong> item on this page is selected."
|
||||||
|
other: All <strong>%{count}</strong> items on this page are selected.
|
||||||
|
all_matching_items_selected_html:
|
||||||
|
one: "<strong>%{count}</strong> item matching your search is selected."
|
||||||
|
other: All <strong>%{count}</strong> items matching your search are selected.
|
||||||
changes_saved_msg: Changes successfully saved!
|
changes_saved_msg: Changes successfully saved!
|
||||||
copy: Copy
|
copy: Copy
|
||||||
delete: Delete
|
delete: Delete
|
||||||
|
deselect: Deselect all
|
||||||
none: None
|
none: None
|
||||||
order_by: Order by
|
order_by: Order by
|
||||||
save_changes: Save changes
|
save_changes: Save changes
|
||||||
|
select_all_matching_items:
|
||||||
|
one: Select %{count} item matching your search.
|
||||||
|
other: Select all %{count} items matching your search.
|
||||||
today: today
|
today: today
|
||||||
validation_errors:
|
validation_errors:
|
||||||
one: Something isn't quite right yet! Please review the error below
|
one: Something isn't quite right yet! Please review the error below
|
||||||
|
|
Loading…
Reference in a new issue