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
This commit is contained in:
parent
b7420b8643
commit
ef0d22f232
7 changed files with 81 additions and 19 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
44
app/models/tag_filter.rb
Normal 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
|
|
@ -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/
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in a new issue