Add search and sort functions to hashtag admin UI (#11829)

* Add search and sort functions to hashtag admin UI

* Move scope processing from tags_controller to tag_filter

* Fix based on method naming conventions

* Fixed not to get 500 errors for invalid requests
signup-info-prompt
mayaeh 2019-09-16 21:27:29 +09:00 committed by Eugen Rochko
parent b7420b8643
commit ef0d22f232
7 changed files with 81 additions and 19 deletions

View File

@ -2,7 +2,6 @@
module Admin module Admin
class TagsController < BaseController class TagsController < BaseController
before_action :set_tags, only: :index
before_action :set_tag, except: [:index, :batch, :approve_all, :reject_all] before_action :set_tag, except: [:index, :batch, :approve_all, :reject_all]
before_action :set_usage_by_domain, except: [:index, :batch, :approve_all, :reject_all] before_action :set_usage_by_domain, except: [:index, :batch, :approve_all, :reject_all]
before_action :set_counters, except: [:index, :batch, :approve_all, :reject_all] before_action :set_counters, except: [:index, :batch, :approve_all, :reject_all]
@ -10,6 +9,7 @@ module Admin
def index def index
authorize :tag, :index? authorize :tag, :index?
@tags = filtered_tags.page(params[:page])
@form = Form::TagBatch.new @form = Form::TagBatch.new
end end
@ -48,10 +48,6 @@ module Admin
private private
def set_tags
@tags = filtered_tags.page(params[:page])
end
def set_tag def set_tag
@tag = Tag.find(params[:id]) @tag = Tag.find(params[:id])
end end
@ -73,16 +69,11 @@ module Admin
end end
def filtered_tags def filtered_tags
scope = Tag TagFilter.new(filter_params).results
scope = scope.discoverable if filter_params[:context] == 'directory'
scope = scope.unreviewed if filter_params[:review] == 'unreviewed'
scope = scope.reviewed.order(reviewed_at: :desc) if filter_params[:review] == 'reviewed'
scope = scope.pending_review.order(requested_review_at: :desc) if filter_params[:review] == 'pending_review'
scope.order(max_score: :desc)
end end
def filter_params def filter_params
params.slice(:context, :review, :page).permit(:context, :review, :page) params.slice(:directory, :reviewed, :unreviewed, :pending_review, :page, :popular, :active, :name).permit(:directory, :reviewed, :unreviewed, :pending_review, :page, :popular, :active, :name)
end end
def tag_params def tag_params

View File

@ -5,7 +5,7 @@ module Admin::FilterHelper
REPORT_FILTERS = %i(resolved account_id target_account_id).freeze REPORT_FILTERS = %i(resolved account_id target_account_id).freeze
INVITE_FILTER = %i(available expired).freeze INVITE_FILTER = %i(available expired).freeze
CUSTOM_EMOJI_FILTERS = %i(local remote by_domain shortcode).freeze CUSTOM_EMOJI_FILTERS = %i(local remote by_domain shortcode).freeze
TAGS_FILTERS = %i(context review).freeze TAGS_FILTERS = %i(directory reviewed unreviewed pending_review popular active name).freeze
INSTANCES_FILTERS = %i(limited by_domain).freeze INSTANCES_FILTERS = %i(limited by_domain).freeze
FOLLOWERS_FILTERS = %i(relationship status by_domain activity order).freeze FOLLOWERS_FILTERS = %i(relationship status by_domain activity order).freeze

View File

@ -39,6 +39,7 @@ class Tag < ApplicationRecord
scope :listable, -> { where(listable: [true, nil]) } scope :listable, -> { where(listable: [true, nil]) }
scope :discoverable, -> { listable.joins(:account_tag_stat).where(AccountTagStat.arel_table[:accounts_count].gt(0)).order(Arel.sql('account_tag_stats.accounts_count desc')) } scope :discoverable, -> { listable.joins(:account_tag_stat).where(AccountTagStat.arel_table[:accounts_count].gt(0)).order(Arel.sql('account_tag_stats.accounts_count desc')) }
scope :most_used, ->(account) { joins(:statuses).where(statuses: { account: account }).group(:id).order(Arel.sql('count(*) desc')) } scope :most_used, ->(account) { joins(:statuses).where(statuses: { account: account }).group(:id).order(Arel.sql('count(*) desc')) }
scope :matches_name, ->(value) { where(arel_table[:name].matches("#{value}%")) }
delegate :accounts_count, delegate :accounts_count,
:accounts_count=, :accounts_count=,

44
app/models/tag_filter.rb Normal file
View File

@ -0,0 +1,44 @@
# frozen_string_literal: true
class TagFilter
attr_reader :params
def initialize(params)
@params = params
end
def results
scope = Tag.unscoped
params.each do |key, value|
next if key.to_s == 'page'
scope.merge!(scope_for(key, value.to_s.strip)) if value.present?
end
scope.order(id: :desc)
end
private
def scope_for(key, value)
case key.to_s
when 'directory'
Tag.discoverable
when 'reviewed'
Tag.reviewed.order(reviewed_at: :desc)
when 'unreviewed'
Tag.unreviewed
when 'pending_review'
Tag.pending_review.order(requested_review_at: :desc)
when 'popular'
Tag.order('max_score DESC NULLS LAST')
when 'active'
Tag.order('last_status_at DESC NULLS LAST')
when 'name'
Tag.matches_name(value)
else
raise "Unknown filter: #{key}"
end
end
end

View File

@ -8,16 +8,36 @@
.filter-subset .filter-subset
%strong= t('admin.tags.context') %strong= t('admin.tags.context')
%ul %ul
%li= filter_link_to t('generic.all'), context: nil %li= filter_link_to t('generic.all'), directory: nil
%li= filter_link_to t('admin.tags.directory'), context: 'directory' %li= filter_link_to t('admin.tags.directory'), directory: '1'
.filter-subset .filter-subset
%strong= t('admin.tags.review') %strong= t('admin.tags.review')
%ul %ul
%li= filter_link_to t('generic.all'), review: nil %li= filter_link_to t('generic.all'), reviewed: nil, unreviewed: nil, pending_review: nil
%li= filter_link_to t('admin.tags.unreviewed'), review: 'unreviewed' %li= filter_link_to t('admin.tags.unreviewed'), unreviewed: '1', reviewed: nil, pending_review: nil
%li= filter_link_to t('admin.tags.reviewed'), review: 'reviewed' %li= filter_link_to t('admin.tags.reviewed'), reviewed: '1', unreviewed: nil, pending_review: nil
%li= filter_link_to safe_join([t('admin.accounts.moderation.pending'), "(#{Tag.pending_review.count})"], ' '), review: 'pending_review' %li= filter_link_to safe_join([t('admin.accounts.moderation.pending'), "(#{Tag.pending_review.count})"], ' '), pending_review: '1', reviewed: nil, unreviewed: nil
.filter-subset
%strong= t('generic.order_by')
%ul
%li= filter_link_to t('admin.tags.most_recent'), popular: nil, active: nil
%li= filter_link_to t('admin.tags.most_popular'), popular: '1', active: nil
%li= filter_link_to t('admin.tags.last_active'), active: '1', popular: nil
= form_tag admin_tags_url, method: 'GET', class: 'simple_form' do
.fields-group
- Admin::FilterHelper::TAGS_FILTERS.each do |key|
= hidden_field_tag key, params[key] if params[key].present?
- %i(name).each do |key|
.input.string.optional
= text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.tags.#{key}")
.actions
%button= t('admin.accounts.search')
= link_to t('admin.accounts.reset'), admin_tags_path, class: 'button negative'
%hr.spacer/ %hr.spacer/

View File

@ -521,6 +521,10 @@ en:
context: Context context: Context
directory: In directory directory: In directory
in_directory: "%{count} in directory" in_directory: "%{count} in directory"
last_active: Last active
most_popular: Most popular
most_recent: Most recent
name: Hashtag
review: Review status review: Review status
reviewed: Reviewed reviewed: Reviewed
title: Hashtags title: Hashtags

View File

@ -131,6 +131,8 @@ en:
must_be_follower: Block notifications from non-followers must_be_follower: Block notifications from non-followers
must_be_following: Block notifications from people you don't follow must_be_following: Block notifications from people you don't follow
must_be_following_dm: Block direct messages from people you don't follow must_be_following_dm: Block direct messages from people you don't follow
invite:
comment: Comment
invite_request: invite_request:
text: Why do you want to join? text: Why do you want to join?
notification_emails: notification_emails: