UX: restore shared sidebar link for posts and drafts (#31159)

While introducing the new drafts dropdown menu component, we also made
some changes to how the sidebar link works for Drafts. However, after
following user feedback and internal discussions we decided to revert
back to the shared link approach that combines My Posts and My Drafts.
This commit is contained in:
David Battersby
2025-02-04 14:40:18 +04:00
committed by GitHub
parent acad83199e
commit 294ed87a6f
9 changed files with 143 additions and 60 deletions

View File

@ -14,7 +14,7 @@ import {
import SectionLink from "discourse/lib/sidebar/section-link";
import AdminSectionLink from "discourse/lib/sidebar/user/community-section/admin-section-link";
import InviteSectionLink from "discourse/lib/sidebar/user/community-section/invite-section-link";
import MyDraftsSectionLink from "discourse/lib/sidebar/user/community-section/my-drafts-section-link";
import MyPostsSectionLink from "discourse/lib/sidebar/user/community-section/my-posts-section-link";
import ReviewSectionLink from "discourse/lib/sidebar/user/community-section/review-section-link";
const SPECIAL_LINKS_MAP = {
@ -22,7 +22,7 @@ const SPECIAL_LINKS_MAP = {
"/about": AboutSectionLink,
"/u": UsersSectionLink,
"/faq": FAQSectionLink,
"/my/activity": MyDraftsSectionLink,
"/my/activity": MyPostsSectionLink,
"/review": ReviewSectionLink,
"/badges": BadgesSectionLink,
"/admin": AdminSectionLink,

View File

@ -4,13 +4,13 @@ import { i18n } from "discourse-i18n";
const USER_DRAFTS_CHANGED_EVENT = "user-drafts:changed";
export default class MyDraftsSectionLink extends BaseSectionLink {
export default class MyPostsSectionLink extends BaseSectionLink {
@tracked draftCount = this.currentUser?.draft_count;
constructor() {
super(...arguments);
if (this.currentUser) {
if (this.shouldDisplay) {
this.appEvents.on(
USER_DRAFTS_CHANGED_EVENT,
this,
@ -20,7 +20,7 @@ export default class MyDraftsSectionLink extends BaseSectionLink {
}
teardown() {
if (this.currentUser) {
if (this.shouldDisplay) {
this.appEvents.off(
USER_DRAFTS_CHANGED_EVENT,
this,
@ -38,11 +38,21 @@ export default class MyDraftsSectionLink extends BaseSectionLink {
}
get name() {
return "my-drafts";
return "my-posts";
}
get route() {
return "userActivity.drafts";
if (this._hasDraft) {
return "userActivity.drafts";
} else {
return "userActivity.index";
}
}
get currentWhen() {
if (this._hasDraft) {
return "userActivity.index userActivity.drafts";
}
}
get model() {
@ -50,11 +60,24 @@ export default class MyDraftsSectionLink extends BaseSectionLink {
}
get title() {
return i18n("sidebar.sections.community.links.my_drafts.title");
if (this._hasDraft) {
return i18n("sidebar.sections.community.links.my_posts.title_drafts");
} else {
return i18n("sidebar.sections.community.links.my_posts.title");
}
}
get text() {
return i18n("sidebar.sections.community.links.my_drafts.content");
if (this._hasDraft && this.currentUser?.new_new_view_enabled) {
return i18n("sidebar.sections.community.links.my_posts.content_drafts");
} else {
return i18n(
`sidebar.sections.community.links.${this.overridenName
.toLowerCase()
.replace(" ", "_")}.content`,
{ defaultValue: this.overridenName }
);
}
}
get badgeText() {
@ -65,7 +88,7 @@ export default class MyDraftsSectionLink extends BaseSectionLink {
if (this.currentUser.new_new_view_enabled) {
return this.draftCount.toString();
} else {
return i18n("sidebar.sections.community.links.my_drafts.draft_count", {
return i18n("sidebar.sections.community.links.my_posts.draft_count", {
count: this.draftCount,
});
}
@ -75,6 +98,13 @@ export default class MyDraftsSectionLink extends BaseSectionLink {
return this.draftCount > 0;
}
get defaultPrefixValue() {
if (this._hasDraft && this.currentUser?.new_new_view_enabled) {
return "pencil";
}
return "user";
}
get suffixCSSClass() {
return "unread";
}
@ -90,10 +120,6 @@ export default class MyDraftsSectionLink extends BaseSectionLink {
}
get shouldDisplay() {
return this.currentUser && this._hasDraft;
}
get prefixValue() {
return "far-pen-to-square";
return this.currentUser;
}
}

View File

@ -481,13 +481,50 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) {
.doesNotExist();
});
test("clicking on my drafts link", async function (assert) {
updateCurrentUser({ draft_count: 1 });
test("clicking on my posts link", async function (assert) {
await visit("/t/280");
await click(
".sidebar-section[data-section-name='community'] .sidebar-section-link[data-link-name='my-posts']"
);
assert.strictEqual(
currentURL(),
`/u/${loggedInUser().username}/activity`,
"should transition to the user's activity url"
);
assert
.dom(
".sidebar-section[data-section-name='community'] .sidebar-section-link.active"
)
.exists({ count: 1 }, "only one link is marked as active");
assert
.dom(
".sidebar-section[data-section-name='community'] .sidebar-section-link[data-link-name='my-posts'].active"
)
.exists("the my posts link is marked as active");
await visit(`/u/${loggedInUser().username}/activity/drafts`);
assert
.dom(
".sidebar-section[data-section-name='community'] .sidebar-section-link[data-link-name='my-posts'].active"
)
.doesNotExist(
"the my posts link is not marked as active when user has no drafts and visiting the user activity drafts URL"
);
});
test("clicking on my posts link when user has a draft", async function (assert) {
await visit("/t/280");
await publishToMessageBus(`/user-drafts/${loggedInUser().id}`, {
draft_count: 1,
});
await click(
".sidebar-section[data-section-name='community'] .sidebar-section-link[data-link-name='my-drafts']"
".sidebar-section[data-section-name='community'] .sidebar-section-link[data-link-name='my-posts']"
);
assert.strictEqual(
@ -504,24 +541,45 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) {
assert
.dom(
".sidebar-section[data-section-name='community'] .sidebar-section-link[data-link-name='my-drafts'].active"
".sidebar-section[data-section-name='community'] .sidebar-section-link[data-link-name='my-posts'].active"
)
.exists("the my drafts link is marked as active");
.exists("the my posts link is marked as active");
await visit(`/u/${loggedInUser().username}/activity`);
assert
.dom(
".sidebar-section[data-section-name='community'] .sidebar-section-link[data-link-name='my-posts'].active"
)
.exists("the my posts link is marked as active");
});
test("my drafts link is visible when user has drafts", async function (assert) {
updateCurrentUser({ draft_count: 1 });
test("my posts title changes when drafts are present", async function (assert) {
await visit("/");
assert
.dom(".sidebar-section-link[data-link-name='my-drafts']")
.exists("my drafts link is displayed when drafts are present");
.dom(".sidebar-section-link[data-link-name='my-posts']")
.hasAttribute(
"title",
i18n("sidebar.sections.community.links.my_posts.title"),
"displays the default title when no drafts are present"
);
await publishToMessageBus(`/user-drafts/${loggedInUser().id}`, {
draft_count: 1,
});
assert
.dom(".sidebar-section-link[data-link-name='my-posts']")
.hasAttribute(
"title",
i18n("sidebar.sections.community.links.my_posts.title_drafts"),
"displays the draft title when drafts are present"
);
});
test("my posts changes its text when drafts are present and new new view experiment is enabled", async function (assert) {
updateCurrentUser({
draft_count: 1,
user_option: {
sidebar_show_count_of_new_items: true,
},
@ -529,17 +587,28 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) {
});
await visit("/");
assert
.dom(".sidebar-section-link[data-link-name='my-posts']")
.hasText(
i18n("sidebar.sections.community.links.my_posts.content"),
"displays the default text when no drafts are present"
);
await publishToMessageBus(`/user-drafts/${loggedInUser().id}`, {
draft_count: 1,
});
assert
.dom(
".sidebar-section-link[data-link-name='my-drafts'] .sidebar-section-link-content-text"
".sidebar-section-link[data-link-name='my-posts'] .sidebar-section-link-content-text"
)
.hasText(
i18n("sidebar.sections.community.links.my_drafts.content"),
i18n("sidebar.sections.community.links.my_posts.content_drafts"),
"displays the text that's appropriate for when drafts are present"
);
assert
.dom(
".sidebar-section-link[data-link-name='my-drafts'] .sidebar-section-link-content-badge"
".sidebar-section-link[data-link-name='my-posts'] .sidebar-section-link-content-badge"
)
.hasText("1", "displays the draft count with no text");
});

View File

@ -14,9 +14,9 @@ class SidebarUrl < ActiveRecord::Base
segment: SidebarUrl.segments["primary"],
},
{
name: "My Drafts",
name: "My Posts",
path: "/my/activity",
icon: "far-pen-to-square",
icon: "user",
segment: SidebarUrl.segments["primary"],
},
{ name: "Review", path: "/review", icon: "flag", segment: SidebarUrl.segments["primary"] },

View File

@ -4979,9 +4979,11 @@ en:
users:
content: "Users"
title: "List of all users"
my_drafts:
content: "My Drafts"
title: "My unposted drafts"
my_posts:
content: "My Posts"
content_drafts: "My Drafts"
title: "My recent topic activity"
title_drafts: "My unposted drafts"
draft_count:
one: "%{count} draft"
other: "%{count} drafts"

View File

@ -24,7 +24,7 @@ RSpec.describe SidebarSection do
expect(community_section.sidebar_section_links.all.map { |link| link.linkable.name }).to eq(
[
"Topics",
"My Drafts",
"My Posts",
"Review",
"Admin",
"Invite",

View File

@ -14,30 +14,12 @@ describe "Drafts dropdown", type: :system do
expect(drafts_dropdown).to be_hidden
end
it "does not have a my drafts link in sidebar" do
page.visit "/"
expect(page).to have_no_css(".sidebar-section-link[data-link-name='my-drafts']")
end
it "adds a draft dropdown menu when a draft is available" do
page.visit "/new-topic"
composer.fill_content("This is a draft")
expect(drafts_dropdown).to be_visible
end
it "shows a my drafts link in sidebar when a draft is saved" do
page.visit "/new-topic"
composer.fill_content("This is a draft")
composer.close
expect(discard_draft_modal).to be_open
discard_draft_modal.click_save
visit "/"
expect(page).to have_css(".sidebar-section-link[data-link-name='my-drafts']")
end
end
describe "with multiple drafts" do

View File

@ -23,7 +23,7 @@ RSpec.describe "Editing Sidebar Community Section", type: :system do
visit("/latest")
expect(sidebar.primary_section_icons("community")).to eq(
%w[layer-group flag wrench paper-plane ellipsis-vertical],
%w[layer-group user flag wrench paper-plane ellipsis-vertical],
)
modal = sidebar.click_community_section_more_button.click_customize_community_section_button
@ -32,10 +32,12 @@ RSpec.describe "Editing Sidebar Community Section", type: :system do
modal.save
modal.confirm_update
expect(sidebar.primary_section_links("community")).to eq(%w[Topics Review Admin Invite More])
expect(sidebar.primary_section_links("community")).to eq(
["My Posts", "Topics", "Review", "Admin", "Invite", "More"],
)
expect(sidebar.primary_section_icons("community")).to eq(
%w[paper-plane flag wrench paper-plane ellipsis-vertical],
%w[user paper-plane flag wrench paper-plane ellipsis-vertical],
)
modal = sidebar.click_community_section_more_button.click_customize_community_section_button
@ -43,10 +45,12 @@ RSpec.describe "Editing Sidebar Community Section", type: :system do
expect(sidebar).to have_section("Community")
expect(sidebar.primary_section_links("community")).to eq(%w[Topics Review Admin Invite More])
expect(sidebar.primary_section_links("community")).to eq(
["Topics", "My Posts", "Review", "Admin", "Invite", "More"],
)
expect(sidebar.primary_section_icons("community")).to eq(
%w[layer-group flag wrench paper-plane ellipsis-vertical],
%w[layer-group user flag wrench paper-plane ellipsis-vertical],
)
end

View File

@ -56,8 +56,8 @@ describe "Viewing sidebar as logged in user", type: :system do
sign_in user
visit("/latest")
links = page.all("#sidebar-section-content-community .sidebar-section-link-wrapper a")
expect(links.map(&:text)).to eq(%w[Tematy])
expect(links.map { |link| link[:title] }).to eq(["Wszystkie tematy"])
expect(links.map(&:text)[0]).to eq("Tematy")
expect(links.map { |link| link[:title] }[0]).to eq("Wszystkie tematy")
end
end