about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--app/controllers/admin/accounts_controller.rb6
-rw-r--r--app/javascript/packs/admin.js53
-rw-r--r--app/javascript/styles/mastodon/tables.scss49
-rw-r--r--app/models/custom_filter_status.rb2
-rw-r--r--app/models/form/account_batch.rb13
-rw-r--r--app/views/admin/accounts/index.html.haml9
-rw-r--r--config/locales/en.yml10
7 files changed, 138 insertions, 4 deletions
diff --git a/app/controllers/admin/accounts_controller.rb b/app/controllers/admin/accounts_controller.rb
index 46c9aba91..40bf685c5 100644
--- a/app/controllers/admin/accounts_controller.rb
+++ b/app/controllers/admin/accounts_controller.rb
@@ -16,7 +16,11 @@ module Admin
     def batch
       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
     rescue ActionController::ParameterMissing
       flash[:alert] = I18n.t('admin.accounts.no_account_selected')
diff --git a/app/javascript/packs/admin.js b/app/javascript/packs/admin.js
index a3ed1ffed..b733d6b18 100644
--- a/app/javascript/packs/admin.js
+++ b/app/javascript/packs/admin.js
@@ -4,18 +4,71 @@ import ready from '../mastodon/ready';
 
 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 }) => {
+  const selectAllMatchingElement = document.querySelector('.batch-table__select-all');
+
   [].forEach.call(document.querySelectorAll(batchCheckboxClassName), (content) => {
     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', () => {
   const checkAllElement = document.querySelector('#batch_checkbox_all');
+  const selectAllMatchingElement = document.querySelector('.batch-table__select-all');
 
   if (checkAllElement) {
     checkAllElement.checked = [].every.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();
+      }
+    }
   }
 });
 
diff --git a/app/javascript/styles/mastodon/tables.scss b/app/javascript/styles/mastodon/tables.scss
index 431b8a73a..39211910f 100644
--- a/app/javascript/styles/mastodon/tables.scss
+++ b/app/javascript/styles/mastodon/tables.scss
@@ -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 {
     padding: 16px;
     border: 1px solid darken($ui-base-color, 8%);
diff --git a/app/models/custom_filter_status.rb b/app/models/custom_filter_status.rb
index b6bea1394..e748d6963 100644
--- a/app/models/custom_filter_status.rb
+++ b/app/models/custom_filter_status.rb
@@ -5,7 +5,7 @@
 #
 #  id               :bigint(8)        not null, primary key
 #  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
 #  updated_at       :datetime         not null
 #
diff --git a/app/models/form/account_batch.rb b/app/models/form/account_batch.rb
index 98f2cad3e..5cfcf7205 100644
--- a/app/models/form/account_batch.rb
+++ b/app/models/form/account_batch.rb
@@ -6,7 +6,8 @@ class Form::AccountBatch
   include AccountableConcern
   include Payloadable
 
-  attr_accessor :account_ids, :action, :current_account
+  attr_accessor :account_ids, :action, :current_account,
+                :select_all_matching, :query
 
   def save
     case action
@@ -60,7 +61,11 @@ class Form::AccountBatch
   end
 
   def accounts
-    Account.where(id: account_ids)
+    if select_all_matching?
+      query
+    else
+      Account.where(id: account_ids)
+    end
   end
 
   def approve!
@@ -118,4 +123,8 @@ class Form::AccountBatch
     log_action(:approve, account.user)
     account.user.approve!
   end
+
+  def select_all_matching?
+    select_all_matching == '1'
+  end
 end
diff --git a/app/views/admin/accounts/index.html.haml b/app/views/admin/accounts/index.html.haml
index cb378f0ed..670a09a2d 100644
--- a/app/views/admin/accounts/index.html.haml
+++ b/app/views/admin/accounts/index.html.haml
@@ -37,6 +37,7 @@
 
 = form_for(@form, url: batch_admin_accounts_path) do |f|
   = hidden_field_tag :page, params[:page] || 1
+  = hidden_field_tag :select_all_matching, '0'
 
   - AccountFilter::KEYS.each do |key|
     = 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('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
       - if @accounts.empty?
         = nothing_here 'nothing-here--under-tabs'
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 5c309ab11..6aa87e4a0 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -1227,12 +1227,22 @@ en:
     trending_now: Trending now
   generic:
     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!
     copy: Copy
     delete: Delete
+    deselect: Deselect all
     none: None
     order_by: Order by
     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
     validation_errors:
       one: Something isn't quite right yet! Please review the error below