mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 09:42:07 +08:00
FEATURE: Add review link to community section for logged in user (#18374)
When there are pending reviewables, the review section link is displayed in the main section. When there are no pending reviewables, the review section link is displayed under the more links drawer. Internal ref: /t/74210
This commit is contained in:
parent
bc97f3d1c1
commit
4b561277a9
|
@ -151,11 +151,11 @@ export default Component.extend({
|
||||||
|
|
||||||
// "fast track" to update the current user's reviewable count before the message bus finds out.
|
// "fast track" to update the current user's reviewable count before the message bus finds out.
|
||||||
if (performResult.reviewable_count !== undefined) {
|
if (performResult.reviewable_count !== undefined) {
|
||||||
this.currentUser.set(
|
this.currentUser.updateReviewableCount(
|
||||||
"reviewable_count",
|
|
||||||
performResult.reviewable_count
|
performResult.reviewable_count
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (performResult.unseen_reviewable_count !== undefined) {
|
if (performResult.unseen_reviewable_count !== undefined) {
|
||||||
this.currentUser.set(
|
this.currentUser.set(
|
||||||
"unseen_reviewable_count",
|
"unseen_reviewable_count",
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import Component from "@glimmer/component";
|
import Component from "@glimmer/component";
|
||||||
import { inject as service } from "@ember/service";
|
import { inject as service } from "@ember/service";
|
||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
customSectionLinks,
|
customSectionLinks,
|
||||||
|
@ -13,29 +14,18 @@ export default class SidebarCommunitySection extends Component {
|
||||||
@service appEvents;
|
@service appEvents;
|
||||||
@service siteSettings;
|
@service siteSettings;
|
||||||
|
|
||||||
|
@tracked sectionLinks;
|
||||||
|
@tracked moreSectionLinks;
|
||||||
|
@tracked moreSecondarySectionLinks;
|
||||||
|
|
||||||
|
callbackId;
|
||||||
headerActionsIcon;
|
headerActionsIcon;
|
||||||
headerActions;
|
headerActions;
|
||||||
sectionLinks;
|
|
||||||
moreSectionLinks;
|
|
||||||
moreSecondarySectionLinks;
|
|
||||||
callbackId;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(...arguments);
|
super(...arguments);
|
||||||
|
|
||||||
this.moreSectionLinks = this.#initializeSectionLinks([
|
this.refreshSectionLinks();
|
||||||
...this.defaultMoreSectionLinks,
|
|
||||||
...customSectionLinks,
|
|
||||||
]);
|
|
||||||
|
|
||||||
this.moreSecondarySectionLinks = this.#initializeSectionLinks([
|
|
||||||
...this.defaultMoreSecondarySectionLinks,
|
|
||||||
...secondaryCustomSectionLinks,
|
|
||||||
]);
|
|
||||||
|
|
||||||
this.sectionLinks = this.#initializeSectionLinks(
|
|
||||||
this.defaultMainSectionLinks
|
|
||||||
);
|
|
||||||
|
|
||||||
this.callbackId = this.topicTrackingState.onStateChange(() => {
|
this.callbackId = this.topicTrackingState.onStateChange(() => {
|
||||||
this.sectionLinks.forEach((sectionLink) => {
|
this.sectionLinks.forEach((sectionLink) => {
|
||||||
|
@ -64,6 +54,22 @@ export default class SidebarCommunitySection extends Component {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
refreshSectionLinks() {
|
||||||
|
this.moreSectionLinks = this.#initializeSectionLinks([
|
||||||
|
...this.defaultMoreSectionLinks,
|
||||||
|
...customSectionLinks,
|
||||||
|
]);
|
||||||
|
|
||||||
|
this.moreSecondarySectionLinks = this.#initializeSectionLinks([
|
||||||
|
...this.defaultMoreSecondarySectionLinks,
|
||||||
|
...secondaryCustomSectionLinks,
|
||||||
|
]);
|
||||||
|
|
||||||
|
this.sectionLinks = this.#initializeSectionLinks(
|
||||||
|
this.defaultMainSectionLinks
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#initializeSectionLinks(sectionLinkClasses) {
|
#initializeSectionLinks(sectionLinkClasses) {
|
||||||
return sectionLinkClasses.reduce((links, sectionLinkClass) => {
|
return sectionLinkClasses.reduce((links, sectionLinkClass) => {
|
||||||
const sectionLink = this.#initializeSectionLink(sectionLinkClass);
|
const sectionLink = this.#initializeSectionLink(sectionLinkClass);
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
{{did-insert this.registerClickListener}}
|
{{did-insert this.registerClickListener}}
|
||||||
{{will-destroy this.unregisterClickListener}} >
|
{{will-destroy this.unregisterClickListener}} >
|
||||||
|
|
||||||
<div class="sidebar-more-section-link-details-content">
|
<div class="sidebar-more-section-links-details-content">
|
||||||
<div class="sidebar-more-section-links-details-content-main">
|
<div class="sidebar-more-section-links-details-content-main">
|
||||||
{{#each this.sectionLinks as |sectionLink|}}
|
{{#each this.sectionLinks as |sectionLink|}}
|
||||||
<Sidebar::MoreSectionLink @sectionLink={{sectionLink}} />
|
<Sidebar::MoreSectionLink @sectionLink={{sectionLink}} />
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
|
|
||||||
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
import Composer from "discourse/models/composer";
|
import Composer from "discourse/models/composer";
|
||||||
import { getOwner } from "discourse-common/lib/get-owner";
|
import { getOwner } from "discourse-common/lib/get-owner";
|
||||||
import PermissionType from "discourse/models/permission-type";
|
import PermissionType from "discourse/models/permission-type";
|
||||||
|
@ -12,6 +13,7 @@ import AboutSectionLink from "discourse/lib/sidebar/common/community-section/abo
|
||||||
import FAQSectionLink from "discourse/lib/sidebar/common/community-section/faq-section-link";
|
import FAQSectionLink from "discourse/lib/sidebar/common/community-section/faq-section-link";
|
||||||
import AdminSectionLink from "discourse/lib/sidebar/user/community-section/admin-section-link";
|
import AdminSectionLink from "discourse/lib/sidebar/user/community-section/admin-section-link";
|
||||||
import BadgesSectionLink from "discourse/lib/sidebar/common/community-section/badges-section-link";
|
import BadgesSectionLink from "discourse/lib/sidebar/common/community-section/badges-section-link";
|
||||||
|
import ReviewSectionLink from "discourse/lib/sidebar/user/community-section/review-section-link";
|
||||||
import SidebarCommonCommunitySection from "discourse/components/sidebar/common/community-section";
|
import SidebarCommonCommunitySection from "discourse/components/sidebar/common/community-section";
|
||||||
|
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
|
@ -29,19 +31,48 @@ export default class SidebarUserCommunitySection extends SidebarCommonCommunityS
|
||||||
title: I18n.t("sidebar.sections.community.header_action_title"),
|
title: I18n.t("sidebar.sections.community.header_action_title"),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
this.appEvents.on(
|
||||||
|
"user-reviewable-count:changed",
|
||||||
|
this._refreshSectionLinks
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
willDestroy() {
|
||||||
|
this.appEvents.off(
|
||||||
|
"user-reviewable-count:changed",
|
||||||
|
this._refreshSectionLinks
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@bind
|
||||||
|
_refreshSectionLinks() {
|
||||||
|
return this.refreshSectionLinks();
|
||||||
}
|
}
|
||||||
|
|
||||||
get defaultMainSectionLinks() {
|
get defaultMainSectionLinks() {
|
||||||
return [
|
const links = [
|
||||||
EverythingSectionLink,
|
EverythingSectionLink,
|
||||||
TrackedSectionLink,
|
TrackedSectionLink,
|
||||||
MyPostsSectionLink,
|
MyPostsSectionLink,
|
||||||
AdminSectionLink,
|
AdminSectionLink,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (this.currentUser.reviewable_count > 0) {
|
||||||
|
links.push(ReviewSectionLink);
|
||||||
|
}
|
||||||
|
|
||||||
|
return links;
|
||||||
}
|
}
|
||||||
|
|
||||||
get defaultMoreSectionLinks() {
|
get defaultMoreSectionLinks() {
|
||||||
return [GroupsSectionLink, UsersSectionLink, BadgesSectionLink];
|
const links = [GroupsSectionLink, UsersSectionLink, BadgesSectionLink];
|
||||||
|
|
||||||
|
if (this.currentUser.reviewable_count === 0) {
|
||||||
|
links.push(ReviewSectionLink);
|
||||||
|
}
|
||||||
|
|
||||||
|
return links;
|
||||||
}
|
}
|
||||||
|
|
||||||
get defaultMoreSecondarySectionLinks() {
|
get defaultMoreSecondarySectionLinks() {
|
||||||
|
|
|
@ -28,10 +28,12 @@ export default {
|
||||||
const channel = user.enable_redesigned_user_menu
|
const channel = user.enable_redesigned_user_menu
|
||||||
? `/reviewable_counts/${user.id}`
|
? `/reviewable_counts/${user.id}`
|
||||||
: "/reviewable_counts";
|
: "/reviewable_counts";
|
||||||
|
|
||||||
bus.subscribe(channel, (data) => {
|
bus.subscribe(channel, (data) => {
|
||||||
if (data.reviewable_count >= 0) {
|
if (data.reviewable_count >= 0) {
|
||||||
user.set("reviewable_count", data.reviewable_count);
|
user.updateReviewableCount(data.reviewable_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.redesigned_user_menu_enabled) {
|
if (user.redesigned_user_menu_enabled) {
|
||||||
user.set("unseen_reviewable_count", data.unseen_reviewable_count);
|
user.set("unseen_reviewable_count", data.unseen_reviewable_count);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import I18n from "I18n";
|
||||||
|
|
||||||
|
import BaseSectionLink from "discourse/lib/sidebar/base-community-section-link";
|
||||||
|
|
||||||
|
export default class ReviewSectionLink extends BaseSectionLink {
|
||||||
|
get name() {
|
||||||
|
return "review";
|
||||||
|
}
|
||||||
|
|
||||||
|
get route() {
|
||||||
|
return "review";
|
||||||
|
}
|
||||||
|
|
||||||
|
get title() {
|
||||||
|
return I18n.t("sidebar.sections.community.links.review.title");
|
||||||
|
}
|
||||||
|
|
||||||
|
get text() {
|
||||||
|
return I18n.t("sidebar.sections.community.links.review.content");
|
||||||
|
}
|
||||||
|
|
||||||
|
get shouldDisplay() {
|
||||||
|
return this.currentUser.can_review;
|
||||||
|
}
|
||||||
|
|
||||||
|
get badgeText() {
|
||||||
|
if (this.currentUser.reviewable_count > 0) {
|
||||||
|
return I18n.t("sidebar.sections.community.links.review.pending_count", {
|
||||||
|
count: this.currentUser.reviewable_count,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1059,6 +1059,11 @@ const User = RestModel.extend({
|
||||||
this.appEvents.trigger("user-drafts:changed");
|
this.appEvents.trigger("user-drafts:changed");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
updateReviewableCount(count) {
|
||||||
|
this.set("reviewable_count", count);
|
||||||
|
this.appEvents.trigger("user-reviewable-count:changed", count);
|
||||||
|
},
|
||||||
|
|
||||||
isInDoNotDisturb() {
|
isInDoNotDisturb() {
|
||||||
return (
|
return (
|
||||||
this.do_not_disturb_until &&
|
this.do_not_disturb_until &&
|
||||||
|
|
|
@ -68,6 +68,7 @@ export default DiscourseRoute.extend({
|
||||||
const channel = this.currentUser.enable_redesigned_user_menu
|
const channel = this.currentUser.enable_redesigned_user_menu
|
||||||
? `/reviewable_counts/${this.currentUser.id}`
|
? `/reviewable_counts/${this.currentUser.id}`
|
||||||
: "/reviewable_counts";
|
: "/reviewable_counts";
|
||||||
|
|
||||||
this.messageBus.subscribe(channel, (data) => {
|
this.messageBus.subscribe(channel, (data) => {
|
||||||
if (data.updates) {
|
if (data.updates) {
|
||||||
this.controller.reviewables.forEach((reviewable) => {
|
this.controller.reviewables.forEach((reviewable) => {
|
||||||
|
@ -82,10 +83,6 @@ export default DiscourseRoute.extend({
|
||||||
|
|
||||||
deactivate() {
|
deactivate() {
|
||||||
this.messageBus.unsubscribe("/reviewable_claimed");
|
this.messageBus.unsubscribe("/reviewable_claimed");
|
||||||
const channel = this.currentUser.enable_redesigned_user_menu
|
|
||||||
? `/reviewable_counts/${this.currentUser.id}`
|
|
||||||
: "/reviewable_counts";
|
|
||||||
this.messageBus.unsubscribe(channel);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
|
|
@ -710,6 +710,86 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("review link is not shown when user cannot review", async function (assert) {
|
||||||
|
updateCurrentUser({ can_review: false });
|
||||||
|
|
||||||
|
await visit("/");
|
||||||
|
|
||||||
|
assert.notOk(
|
||||||
|
exists(".sidebar-section-community .sidebar-section-link-review"),
|
||||||
|
"review link is not shown"
|
||||||
|
);
|
||||||
|
|
||||||
|
await click(
|
||||||
|
".sidebar-section-community .sidebar-more-section-links-details-summary"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.notOk(
|
||||||
|
exists(".sidebar-section-community .sidebar-section-link-review"),
|
||||||
|
"review link is not shown"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("review link when user can review", async function (assert) {
|
||||||
|
updateCurrentUser({
|
||||||
|
can_review: true,
|
||||||
|
reviewable_count: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
await visit("/reivew");
|
||||||
|
|
||||||
|
assert.notOk(
|
||||||
|
exists(".sidebar-section-community .sidebar-section-link-review.active"),
|
||||||
|
"review link is shown as active when visiting the review route even if there are no pending reviewables"
|
||||||
|
);
|
||||||
|
|
||||||
|
await visit("/");
|
||||||
|
|
||||||
|
assert.notOk(
|
||||||
|
exists(".sidebar-section-community .sidebar-section-link-review"),
|
||||||
|
"review link is not shown as part of the main section links"
|
||||||
|
);
|
||||||
|
|
||||||
|
await click(
|
||||||
|
".sidebar-section-community .sidebar-more-section-links-details-summary"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
exists(
|
||||||
|
".sidebar-section-community .sidebar-more-section-links-details-content .sidebar-section-link-review"
|
||||||
|
),
|
||||||
|
"review link is displayed in the more drawer"
|
||||||
|
);
|
||||||
|
|
||||||
|
await publishToMessageBus("/reviewable_counts", {
|
||||||
|
reviewable_count: 34,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
exists(".sidebar-section-community .sidebar-section-link-review"),
|
||||||
|
"review link is shown as part of the main section links"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.strictEqual(
|
||||||
|
query(
|
||||||
|
".sidebar-section-community .sidebar-section-link-review .sidebar-section-link-content-badge"
|
||||||
|
).textContent.trim(),
|
||||||
|
"34 pending",
|
||||||
|
"displays the pending reviewable count"
|
||||||
|
);
|
||||||
|
|
||||||
|
await click(
|
||||||
|
".sidebar-section-community .sidebar-more-section-links-details-summary"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.notOk(
|
||||||
|
exists(
|
||||||
|
".sidebar-section-community .sidebar-more-section-links-details-content .sidebar-section-link-review"
|
||||||
|
),
|
||||||
|
"review link is not displayed in the more drawer"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
test("new and unread count for tracked link", async function (assert) {
|
test("new and unread count for tracked link", async function (assert) {
|
||||||
const categories = Site.current().categories;
|
const categories = Site.current().categories;
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-more-section-link-details-content {
|
.sidebar-more-section-links-details-content {
|
||||||
background-color: var(--secondary);
|
background-color: var(--secondary);
|
||||||
box-shadow: shadow("dropdown");
|
box-shadow: shadow("dropdown");
|
||||||
margin: 0 calc(var(--d-sidebar-row-horizontal-padding) * 2 / 3);
|
margin: 0 calc(var(--d-sidebar-row-horizontal-padding) * 2 / 3);
|
||||||
|
|
|
@ -71,6 +71,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sidebar-section-link-review {
|
||||||
|
.sidebar-section-link-content-badge {
|
||||||
|
color: var(--danger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar-section-link-prefix {
|
.sidebar-section-link-prefix {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
|
|
@ -4196,6 +4196,10 @@ en:
|
||||||
draft_count:
|
draft_count:
|
||||||
one: "%{count} draft"
|
one: "%{count} draft"
|
||||||
other: "%{count} drafts"
|
other: "%{count} drafts"
|
||||||
|
review:
|
||||||
|
content: "Review"
|
||||||
|
title: "review"
|
||||||
|
pending_count: "%{count} pending"
|
||||||
|
|
||||||
welcome_topic_banner:
|
welcome_topic_banner:
|
||||||
title: "Create your Welcome Topic"
|
title: "Create your Welcome Topic"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user