modqueue: add sidebar.
Add a sidebar to the modqueue page that shows the following information: * Number of pending and flagged posts. * Number of posts disapproved for poor quality or breaking rules. * Top uploaders in the queue. * Top artist, copyright, and character tags in the queue.
This commit is contained in:
@@ -1,9 +1,22 @@
|
||||
class ModqueueController < ApplicationController
|
||||
respond_to :html, :json, :xml
|
||||
before_action :approver_only
|
||||
layout "sidebar"
|
||||
|
||||
def index
|
||||
@posts = Post.includes(:appeals, :disapprovals, :uploader, flags: [:creator]).reorder(id: :asc).pending_or_flagged.available_for_moderation(search_params[:hidden]).tag_match(search_params[:tags]).paginated_search(params, count_pages: true)
|
||||
@posts = Post.includes(:appeals, :disapprovals, :uploader, flags: [:creator]).pending_or_flagged.available_for_moderation(search_params[:hidden]).tag_match(search_params[:tags])
|
||||
|
||||
@pending_post_count = @posts.pending.count
|
||||
@flagged_post_count = @posts.flagged.count
|
||||
@disapproval_reasons = PostDisapproval.where(post: @posts).where.not(reason: "disinterest").group(:reason).order(count: :desc).distinct.count(:post_id)
|
||||
@uploaders = @posts.reorder(nil).group(:uploader).order(count: :desc).limit(20).count
|
||||
|
||||
@tags = RelatedTagCalculator.frequent_tags_for_post_relation(@posts)
|
||||
@artist_tags = @tags.select { |tag| tag.category == Tag.categories.artist }.sort_by(&:overlap_count).reverse.take(10)
|
||||
@copyright_tags = @tags.select { |tag| tag.category == Tag.categories.copyright }.sort_by(&:overlap_count).reverse.take(10)
|
||||
@character_tags = @tags.select { |tag| tag.category == Tag.categories.character }.sort_by(&:overlap_count).reverse.take(10)
|
||||
|
||||
@posts = @posts.reorder(id: :asc).paginated_search(params, count_pages: true)
|
||||
respond_with(@posts)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -17,7 +17,11 @@ module RelatedTagCalculator
|
||||
|
||||
def self.frequent_tags_for_search(tag_query, search_sample_size: 1000, category: nil)
|
||||
sample_posts = Post.tag_match(tag_query).reorder(:md5).limit(search_sample_size)
|
||||
tag_counts = Post.from(sample_posts).with_unflattened_tags.group("tag").select("tag, COUNT(*) AS overlap_count")
|
||||
frequent_tags_for_post_relation(sample_posts, category: category)
|
||||
end
|
||||
|
||||
def self.frequent_tags_for_post_relation(posts, category: nil)
|
||||
tag_counts = Post.from(posts).with_unflattened_tags.group("tag").select("tag, COUNT(*) AS overlap_count")
|
||||
|
||||
tags = Tag.from(tag_counts).joins("JOIN tags ON tags.name = tag")
|
||||
tags = tags.select("tags.*, overlap_count")
|
||||
@@ -27,7 +31,7 @@ module RelatedTagCalculator
|
||||
tags
|
||||
end
|
||||
|
||||
def self.frequent_tags_for_posts(posts)
|
||||
def self.frequent_tags_for_post_array(posts)
|
||||
tags_with_counts = posts.flat_map(&:tag_array).group_by(&:itself).transform_values(&:size)
|
||||
tags_with_counts.sort_by { |tag_name, count| [-count, tag_name] }.map(&:first)
|
||||
end
|
||||
|
||||
@@ -44,7 +44,7 @@ module PostSetPresenters
|
||||
end
|
||||
|
||||
def frequent_tags
|
||||
RelatedTagCalculator.frequent_tags_for_posts(post_set.posts).take(MAX_TAGS)
|
||||
RelatedTagCalculator.frequent_tags_for_post_array(post_set.posts).take(MAX_TAGS)
|
||||
end
|
||||
|
||||
def pattern_tags
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
<% content_for(:layout) do %>
|
||||
<div id="c-<%= params[:controller].parameterize.dasherize %>">
|
||||
<div id="a-<%= params[:action].parameterize.dasherize %>" class="sidebar-container">
|
||||
<aside id="sidebar">
|
||||
<%= yield :sidebar %>
|
||||
</aside>
|
||||
<div id="a-<%= params[:action].parameterize.dasherize %>">
|
||||
<% if content_for(:top_content).present? %>
|
||||
<section id="top-content">
|
||||
<%= yield :top_content %>
|
||||
</section>
|
||||
<% end %>
|
||||
|
||||
<section id="content">
|
||||
<%= yield :content %>
|
||||
</section>
|
||||
<div class="sidebar-container">
|
||||
<aside id="sidebar">
|
||||
<%= yield :sidebar %>
|
||||
</aside>
|
||||
|
||||
<section id="content">
|
||||
<%= yield :content %>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
54
app/views/modqueue/_sidebar.html.erb
Normal file
54
app/views/modqueue/_sidebar.html.erb
Normal file
@@ -0,0 +1,54 @@
|
||||
<% content_for(:sidebar) do %>
|
||||
<h2>Search</h2>
|
||||
|
||||
<%= search_form_for(modqueue_index_path, classes: "one-line-form") do |f| %>
|
||||
<%= f.input :tags, label: false, input_html: { placeholder: "Tags", value: params.dig(:search, :tags), "data-autocomplete": "tag-query" } %>
|
||||
<%= f.button :button, name: nil, id: "search-box-submit" do %>
|
||||
<i class="fas fa-search"></i>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<%= render "posts/partials/index/blacklist" %>
|
||||
|
||||
<p id="modqueue-sidebar-status" class="sidebar-section">
|
||||
<h6>Status</h6>
|
||||
<ul>
|
||||
<li>
|
||||
<%= link_to "status:pending", modqueue_index_path(search: { tags: "status:pending" }) %>
|
||||
<span class="post-count"><%= @pending_post_count %></span>
|
||||
</li>
|
||||
<li>
|
||||
<%= link_to "status:flagged", modqueue_index_path(search: { tags: "status:flagged" }) %>
|
||||
<span class="post-count"><%= @flagged_post_count %></span>
|
||||
</li>
|
||||
|
||||
<% @disapproval_reasons.each do |reason, count| %>
|
||||
<li>
|
||||
<%= link_to "disapproved:#{reason}", modqueue_index_path(search: { tags: "disapproved:#{reason}" }) %>
|
||||
<span class="post-count"><%= count %></span>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<p id="modqueue-sidebar-uploaders" class="sidebar-section">
|
||||
<h6>Uploaders</h6>
|
||||
<ul>
|
||||
<% @uploaders.each do |uploader, count| %>
|
||||
<li>
|
||||
<%= link_to_user uploader %>
|
||||
<%= link_to "»", modqueue_index_path(search: { tags: "user:#{uploader.name}" }) %>
|
||||
<span class="post-count"><%= count %></span>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<p id="modqueue-sidebar-tags" class="sidebar-section">
|
||||
<h6>Tags</h6>
|
||||
|
||||
<%= render "tag_list", tags: @artist_tags %>
|
||||
<%= render "tag_list", tags: @copyright_tags %>
|
||||
<%= render "tag_list", tags: @character_tags %>
|
||||
</p>
|
||||
<% end %>
|
||||
10
app/views/modqueue/_tag_list.html.erb
Normal file
10
app/views/modqueue/_tag_list.html.erb
Normal file
@@ -0,0 +1,10 @@
|
||||
<ul>
|
||||
<% tags.each do |tag| %>
|
||||
<li>
|
||||
<%= link_to "?", wiki_page_path(tag.name), class: tag_class(tag) %>
|
||||
<%= link_to tag.pretty_name, posts_path(tags: tag.name), class: tag_class(tag) %>
|
||||
<%= link_to "»", modqueue_index_path(search: { tags: tag.name }), class: tag_class(tag) %>
|
||||
<span class="post-count"><%= tag.overlap_count %></span>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
@@ -1,39 +1,33 @@
|
||||
<% page_title "Mod Queue" %>
|
||||
<% page_title "Moderation Queue" %>
|
||||
|
||||
<div id="c-modqueue">
|
||||
<div id="a-index">
|
||||
<div>
|
||||
<h1>Moderation Queue</h1>
|
||||
<% content_for(:top_content) do %>
|
||||
<h1>Moderation Queue</h1>
|
||||
|
||||
<%= search_form_for(modqueue_index_path) do |f| %>
|
||||
<%= f.input :tags, input_html: { value: params.dig(:search, :tags), "data-autocomplete": "tag-query" } %>
|
||||
<%= f.submit "Search" %>
|
||||
<div id="moderation-guideline" class="fixed-width-container">
|
||||
<h2>Deletion Guidelines</h2>
|
||||
|
||||
<%= render "desc" %>
|
||||
|
||||
<p>
|
||||
<% if params.dig(:search, :hidden) %>
|
||||
<%= link_to "View pending posts", modqueue_index_path(search: { tags: params.dig(:search, :tags), hidden: nil }) %>.
|
||||
<% else %>
|
||||
<%= link_to "View hidden posts", modqueue_index_path(search: { tags: params.dig(:search, :tags), hidden: true, }) %>.
|
||||
<% end %>
|
||||
|
||||
<div id="moderation-guideline" class="fixed-width-container">
|
||||
<h2>Deletion Guidelines</h2>
|
||||
|
||||
<%= render "desc" %>
|
||||
|
||||
<p>
|
||||
<% if params.dig(:search, :hidden) %>
|
||||
<%= link_to "View pending posts", modqueue_index_path(search: { tags: params.dig(:search, :tags), hidden: nil }) %>.
|
||||
<% else %>
|
||||
<%= link_to "View hidden posts", modqueue_index_path(search: { tags: params.dig(:search, :tags), hidden: true, }) %>.
|
||||
<% end %>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<%= render "posts/partials/common/inline_blacklist" %>
|
||||
|
||||
<% @posts.each do |post| %>
|
||||
<%= render "post", post: post %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<%= numbered_paginator(@posts) %>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% content_for(:content) do %>
|
||||
<h2>Posts</h2>
|
||||
|
||||
<% @posts.each do |post| %>
|
||||
<%= render "post", post: post %>
|
||||
<% end %>
|
||||
|
||||
<%= numbered_paginator(@posts) %>
|
||||
<% end %>
|
||||
|
||||
<%= render "modqueue/sidebar" %>
|
||||
<%= render "post_disapprovals/detailed_rejection_dialog" %>
|
||||
<%= render "posts/partials/common/secondary_links" %>
|
||||
|
||||
@@ -13,14 +13,14 @@ class RelatedTagCalculatorTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
context "RelatedTagCalculator" do
|
||||
context "#frequent_tags_for_posts" do
|
||||
context "#frequent_tags_for_post_array" do
|
||||
should "calculate the most frequent tags for a set of posts" do
|
||||
create(:post, tag_string: "aaa bbb ccc ddd")
|
||||
create(:post, tag_string: "aaa bbb ccc")
|
||||
create(:post, tag_string: "aaa bbb")
|
||||
posts = Post.tag_match("aaa")
|
||||
|
||||
assert_equal(%w[aaa bbb ccc ddd], RelatedTagCalculator.frequent_tags_for_posts(posts))
|
||||
assert_equal(%w[aaa bbb ccc ddd], RelatedTagCalculator.frequent_tags_for_post_array(posts))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user