Add new members filter to mod center (#20542)

* fix jest

* Update safe_params_list.vcl

---------

Co-authored-by: Ben Halpern <bendhalpern@gmail.com>
This commit is contained in:
Philip How 2024-01-23 21:07:45 +00:00 committed by GitHub
parent 321540ec08
commit d615fcef56
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 64 additions and 7 deletions

View file

@ -169,3 +169,21 @@
margin-top: var(--su-6);
margin-left: var(--su-3);
}
.mod-filter {
display: grid;
gap: var(--layout-gap);
grid-template-columns: var(--layout);
padding-top: var(--layout-padding);
padding-bottom: var(--layout-padding);
&__item {
display: flex;
align-items: center;
}
&__label {
font-weight: var(--fw-medium);
margin-right: var(--su-3);
}
}

View file

@ -5,7 +5,7 @@ class ModerationsController < ApplicationController
SCORE_MAX = 5
JSON_OPTIONS = {
only: %i[id title published_at cached_tag_list path],
only: %i[id title published_at cached_tag_list path nth_published_by_author],
include: {
user: { only: %i[username name path articles_count id] }
}
@ -16,6 +16,7 @@ class ModerationsController < ApplicationController
return unless current_user&.trusted?
@feed = params[:state] == "latest" ? "latest" : "inbox"
@members = params[:members].in?(%w[new not_new]) ? params[:members] : "all"
articles = Article.published
.order(published_at: :desc).limit(70)
articles = articles.cached_tagged_with(params[:tag]) if params[:tag].present?
@ -26,9 +27,10 @@ class ModerationsController < ApplicationController
.where("articles.score >= ? AND articles.score <= ?", SCORE_MIN, SCORE_MAX)
.where(reactions: { id: nil })
end
if params[:state] == "new-authors"
articles = articles.where("nth_published_by_author > 0 AND nth_published_by_author < 4 AND published_at > ?",
7.days.ago)
if @members == "new"
articles = articles.where("nth_published_by_author > 0 AND nth_published_by_author < 4")
elsif @members == "not_new"
articles = articles.where("nth_published_by_author > 3")
end
@articles = articles.includes(:user).to_json(JSON_OPTIONS)
@tag = Tag.find_by(name: params[:tag]) || not_found if params[:tag].present?

View file

@ -53,6 +53,7 @@ export class ModerationArticles extends Component {
path,
cached_tag_list: cachedTagList,
published_at: publishedAt,
nth_published_by_author: nthPublishedByAuthor,
user,
} = article;
return (
@ -63,6 +64,7 @@ export class ModerationArticles extends Component {
cachedTagList={cachedTagList}
key={id}
publishedAt={publishedAt}
nthPublishedByAuthor={nthPublishedByAuthor}
user={user}
articleOpened={id === prevSelectedArticleId}
toggleArticle={this.toggleArticle}

View file

@ -14,6 +14,7 @@ const getTestArticle = () => ({
articles_count: 1,
name: 'hello',
},
nthPublishedByAuthor: 1,
});
describe('<SingleArticle />', () => {
@ -94,7 +95,7 @@ describe('<SingleArticle />', () => {
expect(text).toContain(getTestArticle().user.name);
});
it('renders the hand wave emoji if the author has less than 3 articles', () => {
it("renders the hand wave emoji if the article is the author's first, second or third", () => {
const { container } = render(
<Fragment>
<SingleArticle {...getTestArticle()} toggleArticle={jest.fn()} />

View file

@ -7,6 +7,7 @@ export const SingleArticle = ({
title,
publishedAt,
cachedTagList,
nthPublishedByAuthor,
user,
key,
articleOpened,
@ -28,7 +29,7 @@ export const SingleArticle = ({
const tags = cachedTagList.split(', ').map((tag) => tagsFormat(tag, key));
const newAuthorNotification = user.articles_count <= 3 ? '👋 ' : '';
const newAuthorNotification = nthPublishedByAuthor <= 3 ? '👋 ' : '';
return (
<Fragment>

View file

@ -21,6 +21,26 @@
<div class="crayons-notice mb-4 border-2 border-solid border-accent-brand">
<%= t("views.moderations.feed.#{@feed}_html") %>
</div>
<%= form_tag(request.path, method: :get, id: "members_filter_form") do %>
<div class="mod-filter">
<div class="crayons-layout__content mod-filter__item">
<label class="mod-filter__label" for="members"><%= t("views.moderations.members.label") %>:</label>
<%= select_tag :members,
options_for_select(
{
t("views.moderations.members.all") => "",
t("views.moderations.members.new") => "new",
t("views.moderations.members.established") => "not_new"
},
params[:members],
),
{ class: "crayons-select crayons-input-sm", "aria-label": t("views.moderations.members.filter"),
onchange: "this.form.submit();" } %>
<%= hidden_field_tag :state, params[:state] %>
</div>
</div>
<% end %>
<section class="mod-index-body">
<div class="mod-index-list-header lh-tight hidden m:grid">
<h2 class="mod-index-list-header__label"><%= t("views.moderations.post") %></h2>

View file

@ -2,6 +2,6 @@ import querystring;
sub vcl_recv {
# return this URL with only the parameters that match this regular expression
if (req.url !~ "/admin/" && req.url !~ "/search/" && req.url !~ "/bulk_show") {
set req.url = querystring.regfilter_except(req.url, "^(a_id|args|article_id|article_ids|articles|asc|callback_url|category|client_id|code|collection_id|commentable_id|commentable_type|confirmation_token|created_at|end|email|filter|followable_id|followable_type|forem_owner_secret|fork_id|i|key|message_offset|name|oauth_token|oauth_verifier|offset|onboarding|org_id|organization_id|p|page|per_page|p_id|placement_area|prefill|preview|purchaser|q|reactable_ids|redirect_uri|reported_url|reporter_username|response_type|scope|search|signature|sort|source_id|source_type|start|state|status|tag|tag_list|top|type_of|url|username|invitation_token|reset_password_token|ut|verb|invitation_slug|period|comments_sort|billboard|controller_action|bb_test_placement_area|cookies_allowed|bb_test_id)$");
set req.url = querystring.regfilter_except(req.url, "^(a_id|args|article_id|article_ids|articles|asc|callback_url|category|client_id|code|collection_id|commentable_id|commentable_type|confirmation_token|created_at|end|email|filter|followable_id|followable_type|forem_owner_secret|fork_id|i|key|message_offset|name|oauth_token|oauth_verifier|offset|onboarding|org_id|organization_id|p|page|per_page|p_id|placement_area|prefill|preview|purchaser|q|reactable_ids|redirect_uri|reported_url|reporter_username|response_type|scope|search|signature|sort|source_id|source_type|start|state|status|tag|tag_list|top|type_of|url|username|invitation_token|reset_password_token|ut|verb|invitation_slug|period|comments_sort|billboard|controller_action|bb_test_placement_area|cookies_allowed|members|bb_test_id)$");
}
}

View file

@ -201,3 +201,9 @@ en:
no_flags: Article has no flags.
no_quality_reactions: Article has no quality reactions by trusted users.
title: Moderator actions
members:
all: All
new: New
established: Established
filter: Filter by Members
label: 'Members'

View file

@ -200,3 +200,10 @@ fr:
no_flags: L'article n'a pas de drapeaux.
no_quality_reactions: L'article n'a pas de réactions de qualité par des utilisateurs de confiance
title: Actions privilégiées
members:
all: Tous les membres
new: Nouveaux membres
established: Membres établis
filter: Filtrer par membres
label: 'Membres'