Implement UI for Admin Search of Hashtags (#30880)

This commit is contained in:
Emelia Smith 2024-07-29 17:49:44 +02:00 committed by GitHub
commit c40e481169
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 316 additions and 11 deletions

View file

@ -2,7 +2,15 @@
module Admin
class TagsController < BaseController
before_action :set_tag
before_action :set_tag, except: [:index]
PER_PAGE = 20
def index
authorize :tag, :index?
@tags = filtered_tags.page(params[:page]).per(PER_PAGE)
end
def show
authorize @tag, :show?
@ -31,5 +39,13 @@ module Admin
def tag_params
params.require(:tag).permit(:name, :display_name, :trendable, :usable, :listable)
end
def filtered_tags
TagFilter.new(filter_params.with_defaults(order: 'newest')).results
end
def filter_params
params.slice(:page, *TagFilter::KEYS).permit(:page, *TagFilter::KEYS)
end
end
end

View file

@ -0,0 +1,15 @@
# frozen_string_literal: true
module Admin::TagsHelper
def admin_tags_moderation_options
[
[t('admin.tags.moderation.reviewed'), 'reviewed'],
[t('admin.tags.moderation.review_requested'), 'review_requested'],
[t('admin.tags.moderation.unreviewed'), 'unreviewed'],
[t('admin.tags.moderation.trendable'), 'trendable'],
[t('admin.tags.moderation.not_trendable'), 'not_trendable'],
[t('admin.tags.moderation.usable'), 'usable'],
[t('admin.tags.moderation.not_usable'), 'not_usable'],
]
end
end

View file

@ -350,6 +350,10 @@
color: $primary-text-color;
font-weight: 700;
}
.warning-hint {
font-weight: normal !important;
}
}
&__body {

View file

@ -286,6 +286,10 @@ a.table-action-link {
padding: 0;
}
&--padded {
padding: 12px 16px 16px;
}
&--with-image {
display: flex;
align-items: center;

View file

@ -0,0 +1,74 @@
# frozen_string_literal: true
class Admin::TagFilter
KEYS = %i(
status
name
order
).freeze
attr_reader :params
def initialize(params)
@params = params.to_h.symbolize_keys
end
def results
scope = Tag.reorder(nil)
params.each do |key, value|
next if key == :page
scope.merge!(scope_for(key, value)) if value.present?
end
scope
end
private
def scope_for(key, value)
case key
when :status
status_scope(value)
when :name
Tag.search_for(value.to_s.strip, params[:limit], params[:offset], exclude_unlistable: false)
when :order
order_scope(value)
else
raise Mastodon::InvalidParameterError, "Unknown filter: #{key}"
end
end
def status_scope(value)
case value.to_s
when 'reviewed'
Tag.reviewed
when 'review_requested'
Tag.pending_review
when 'unreviewed'
Tag.unreviewed
when 'trendable'
Tag.trendable
when 'not_trendable'
Tag.not_trendable
when 'usable'
Tag.usable
when 'not_usable'
Tag.not_usable
else
raise Mastodon::InvalidParameterError, "Unknown status: #{value}"
end
end
def order_scope(value)
case value.to_s
when 'newest'
Tag.order(created_at: :desc)
when 'oldest'
Tag.order(created_at: :asc)
else
raise Mastodon::InvalidParameterError, "Unknown order: #{value}"
end
end
end

View file

@ -52,6 +52,7 @@ class Tag < ApplicationRecord
scope :unreviewed, -> { where(reviewed_at: nil) }
scope :pending_review, -> { unreviewed.where.not(requested_review_at: nil) }
scope :usable, -> { where(usable: [true, nil]) }
scope :not_usable, -> { where(usable: false) }
scope :listable, -> { where(listable: [true, nil]) }
scope :trendable, -> { Setting.trendable_by_default ? where(trendable: [true, nil]) : where(trendable: true) }
scope :not_trendable, -> { where(trendable: false) }
@ -74,6 +75,10 @@ class Tag < ApplicationRecord
attributes['display_name'] || name
end
def formatted_name
"##{display_name}"
end
def usable
boolean_with_default('usable', true)
end
@ -132,8 +137,10 @@ class Tag < ApplicationRecord
def search_for(term, limit = 5, offset = 0, options = {})
stripped_term = term.strip
options.reverse_merge!({ exclude_unlistable: true, exclude_unreviewed: false })
query = Tag.listable.matches_name(stripped_term)
query = Tag.matches_name(stripped_term)
query = query.merge(Tag.listable) if options[:exclude_unlistable]
query = query.merge(matching_name(stripped_term).or(where.not(reviewed_at: nil))) if options[:exclude_unreviewed]
query.order(Arel.sql('length(name) ASC, name ASC'))

View file

@ -0,0 +1,27 @@
.batch-table__row{ class: [!tag.requires_review? && !tag.usable? && 'batch-table__row--muted'] }
.batch-table__row__content.batch-table__row__content--padded.pending-account
.pending-account__header
%strong
= link_to tag.formatted_name, admin_tag_path(tag.id)
%br/
- if tag.usable?
= t('admin.tags.moderation.usable')
- else
= t('admin.tags.moderation.not_usable')
·
- if tag.trendable?
= t('admin.tags.moderation.trendable')
- else
= t('admin.tags.moderation.not_trendable')
- if tag.requested_review? || tag.requires_review?
·
- if tag.requested_review?
%span.negative-hint
= t('admin.tags.moderation.review_requested')
- else
%span.warning-hint
= t('admin.tags.moderation.pending_review')

View file

@ -0,0 +1,39 @@
- content_for :page_title do
= t('admin.tags.title')
= form_with url: admin_tags_url, method: :get, class: :simple_form do |form|
.filters
.filter-subset.filter-subset--with-select
%strong= t('admin.tags.moderation.title')
.input.select.optional
= form.select :status,
options_for_select(admin_tags_moderation_options, params[:status]),
prompt: t('generic.all')
.filter-subset.filter-subset--with-select
%strong= t 'generic.order_by'
.input.select
= form.select :order,
options_for_select([[t('admin.tags.newest'), 'newest'], [t('admin.tags.oldest'), 'oldest']], params[:order])
.fields-group
.input.string.optional
= form.text_field :name,
value: params[:name],
class: 'string optional',
placeholder: t('admin.tags.name')
.actions
%button.button= t('admin.tags.search')
= link_to t('admin.tags.reset'), admin_tags_path, class: 'button negative'
%hr.spacer/
.batch-table
.batch-table__body
- if @tags.empty?
= nothing_here 'nothing-here--under-tabs'
- else
= render partial: 'tag', collection: @tags
= paginate @tags

View file

@ -1,12 +1,13 @@
- content_for :page_title do
= "##{@tag.display_name}"
= @tag.formatted_name
- if current_user.can?(:view_dashboard)
- content_for :heading_actions do
- content_for :heading_actions do
- if current_user.can?(:view_dashboard)
= l(@time_period.first)
= ' - '
= l(@time_period.last)
- if current_user.can?(:view_dashboard)
.dashboard
.dashboard__item
= react_admin_component :counter,

View file

@ -4,9 +4,7 @@
.batch-table__row__content.pending-account
.pending-account__header
= link_to admin_tag_path(tag.id) do
= material_symbol 'tag'
= tag.display_name
= link_to tag.formatted_name, admin_tag_path(tag.id)
%br/