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 | ||||
|   class TagsController < BaseController | ||||
|     before_action :set_tags, only: :index | ||||
|     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_counters, except: [:index, :batch, :approve_all, :reject_all] | ||||
|  | @ -10,6 +9,7 @@ module Admin | |||
|     def index | ||||
|       authorize :tag, :index? | ||||
| 
 | ||||
|       @tags = filtered_tags.page(params[:page]) | ||||
|       @form = Form::TagBatch.new | ||||
|     end | ||||
| 
 | ||||
|  | @ -48,10 +48,6 @@ module Admin | |||
| 
 | ||||
|     private | ||||
| 
 | ||||
|     def set_tags | ||||
|       @tags = filtered_tags.page(params[:page]) | ||||
|     end | ||||
| 
 | ||||
|     def set_tag | ||||
|       @tag = Tag.find(params[:id]) | ||||
|     end | ||||
|  | @ -73,16 +69,11 @@ module Admin | |||
|     end | ||||
| 
 | ||||
|     def filtered_tags | ||||
|       scope = Tag | ||||
|       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) | ||||
|       TagFilter.new(filter_params).results | ||||
|     end | ||||
| 
 | ||||
|     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 | ||||
| 
 | ||||
|     def tag_params | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ module Admin::FilterHelper | |||
|   REPORT_FILTERS       = %i(resolved account_id target_account_id).freeze | ||||
|   INVITE_FILTER        = %i(available expired).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 | ||||
|   FOLLOWERS_FILTERS    = %i(relationship status by_domain activity order).freeze | ||||
| 
 | ||||
|  |  | |||
|  | @ -39,6 +39,7 @@ class Tag < ApplicationRecord | |||
|   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 :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, | ||||
|            :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 | ||||
|     %strong= t('admin.tags.context') | ||||
|     %ul | ||||
|       %li= filter_link_to t('generic.all'), context: nil | ||||
|       %li= filter_link_to t('admin.tags.directory'), context: 'directory' | ||||
|       %li= filter_link_to t('generic.all'), directory: nil | ||||
|       %li= filter_link_to t('admin.tags.directory'), directory: '1' | ||||
| 
 | ||||
|   .filter-subset | ||||
|     %strong= t('admin.tags.review') | ||||
|     %ul | ||||
|       %li= filter_link_to t('generic.all'), review: nil | ||||
|       %li= filter_link_to t('admin.tags.unreviewed'), review: 'unreviewed' | ||||
|       %li= filter_link_to t('admin.tags.reviewed'), review: 'reviewed' | ||||
|       %li= filter_link_to safe_join([t('admin.accounts.moderation.pending'), "(#{Tag.pending_review.count})"], ' '), review: 'pending_review' | ||||
|       %li= filter_link_to t('generic.all'), reviewed: nil, unreviewed: nil, pending_review: nil | ||||
|       %li= filter_link_to t('admin.tags.unreviewed'), unreviewed: '1', reviewed: nil, pending_review: nil | ||||
|       %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})"], ' '), 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/ | ||||
| 
 | ||||
|  |  | |||
|  | @ -521,6 +521,10 @@ en: | |||
|       context: Context | ||||
|       directory: In directory | ||||
|       in_directory: "%{count} in directory" | ||||
|       last_active: Last active | ||||
|       most_popular: Most popular | ||||
|       most_recent: Most recent | ||||
|       name: Hashtag | ||||
|       review: Review status | ||||
|       reviewed: Reviewed | ||||
|       title: Hashtags | ||||
|  |  | |||
|  | @ -131,6 +131,8 @@ en: | |||
|         must_be_follower: Block notifications from non-followers | ||||
|         must_be_following: Block notifications from people you don't follow | ||||
|         must_be_following_dm: Block direct messages from people you don't follow | ||||
|       invite: | ||||
|         comment: Comment | ||||
|       invite_request: | ||||
|         text: Why do you want to join? | ||||
|       notification_emails: | ||||
|  |  | |||
		Reference in a new issue