mirror of
https://github.com/discourse/discourse.git
synced 2026-08-17 00:15:02 -05:00
FEATURE: Always show All, Topics, and Replies subtabs for unified new (#35292)
Currently, if a user is part of a group in `experimental_new_new_view_groups`, they will see tabs for All, Topics, and Replies underneath the New tab in the /new topic list. However, if one of the tabs has no topics (i.e. no more unread replies or no more new topics), we hide the tabs entirely. This can be confusing and inconsistent for members. This commit changes the behavior so that the tabs are always shown. Also, we change the text and route of the empty topic list CTA based on the subtab the user is on: * Topics subtab, when there are new Replies: * Button text: Browse new replies * Button points to the Replies subtab * Replies subtab, when there are new Topics: * Button text: Browse new topics * Button points to Topics subtab * All subtab, or any subtab when there are no new topics of any kind: * Button text: Browse latest topics * Button points to /latest
This commit is contained in:
@@ -33,7 +33,6 @@ export default class DiscoveryTopics extends Component {
|
||||
@service documentTitle;
|
||||
@service currentUser;
|
||||
@service topicTrackingState;
|
||||
@service site;
|
||||
|
||||
@tracked loadingNew;
|
||||
|
||||
@@ -184,11 +183,7 @@ export default class DiscoveryTopics extends Component {
|
||||
}
|
||||
|
||||
get renderNewListHeaderControls() {
|
||||
return (
|
||||
this.site.mobileView &&
|
||||
this.showTopicsAndRepliesToggle &&
|
||||
!this.args.bulkSelectEnabled
|
||||
);
|
||||
return this.showTopicsAndRepliesToggle && !this.args.bulkSelectEnabled;
|
||||
}
|
||||
|
||||
get expandGloballyPinned() {
|
||||
@@ -327,12 +322,8 @@ export default class DiscoveryTopics extends Component {
|
||||
@topics={{@model.topics}}
|
||||
@discoveryList={{true}}
|
||||
@focusLastVisitedTopic={{true}}
|
||||
@showTopicsAndRepliesToggle={{this.showTopicsAndRepliesToggle}}
|
||||
@newListSubset={{@model.params.subset}}
|
||||
@changeNewListSubset={{@changeNewListSubset}}
|
||||
@newRepliesCount={{this.newRepliesCount}}
|
||||
@newTopicsCount={{this.newTopicsCount}}
|
||||
/>
|
||||
|
||||
<LoadMore @action={{this.loadMore}} />
|
||||
{{/if}}
|
||||
|
||||
@@ -413,6 +404,12 @@ export default class DiscoveryTopics extends Component {
|
||||
<EmptyTopicFilter
|
||||
@newFilter={{this.new}}
|
||||
@unreadFilter={{this.unread}}
|
||||
@trackingCounts={{hash
|
||||
newTopics=this.newTopicsCount
|
||||
newReplies=this.newRepliesCount
|
||||
}}
|
||||
@changeNewListSubset={{@changeNewListSubset}}
|
||||
@newListSubset={{@model.params.subset}}
|
||||
/>
|
||||
{{/if}}
|
||||
</:afterMessage>
|
||||
|
||||
@@ -21,12 +21,49 @@ export default class EmptyTopicFilter extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
get ctaLabelWithAction() {
|
||||
if (this.currentUser.new_new_view_enabled) {
|
||||
if (this.args.newListSubset === "topics") {
|
||||
if (this.args.trackingCounts.newReplies > 0) {
|
||||
return {
|
||||
action: () => this.args.changeNewListSubset("replies"),
|
||||
label: i18n("topic.browse_new_replies"),
|
||||
};
|
||||
} else {
|
||||
return { action: null, label: i18n("topic.browse_latest_topics") };
|
||||
}
|
||||
}
|
||||
|
||||
if (this.args.newListSubset === "replies") {
|
||||
if (this.args.trackingCounts.newTopics > 0) {
|
||||
return {
|
||||
action: () => this.args.changeNewListSubset("topics"),
|
||||
label: i18n("topic.browse_new_topics"),
|
||||
};
|
||||
} else {
|
||||
return { action: null, label: i18n("topic.browse_latest_topics") };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { action: null, label: i18n("topic.browse_latest_topics") };
|
||||
}
|
||||
|
||||
get ctaRoute() {
|
||||
if (this.currentUser.new_new_view_enabled && this.args.newListSubset) {
|
||||
return;
|
||||
}
|
||||
|
||||
return "discovery.latest";
|
||||
}
|
||||
|
||||
<template>
|
||||
<EmptyState
|
||||
@identifier="empty-topic-filter"
|
||||
@title={{this.educationText}}
|
||||
@ctaLabel={{i18n "topic.browse_latest_topics"}}
|
||||
@ctaRoute="discovery.latest"
|
||||
@ctaLabel={{this.ctaLabelWithAction.label}}
|
||||
@ctaRoute={{this.ctaRoute}}
|
||||
@ctaAction={{this.ctaLabelWithAction.action}}
|
||||
@tipIcon="circle-info"
|
||||
@tipText={{htmlSafe
|
||||
(i18n
|
||||
|
||||
@@ -19,12 +19,7 @@ const Header = <template>
|
||||
@showBulkToggle={{@toggleInTitle}}
|
||||
@canBulkSelect={{@canBulkSelect}}
|
||||
@canDoBulkActions={{@canDoBulkActions}}
|
||||
@showTopicsAndRepliesToggle={{@showTopicsAndRepliesToggle}}
|
||||
@newListSubset={{@newListSubset}}
|
||||
@newRepliesCount={{@newRepliesCount}}
|
||||
@newTopicsCount={{@newTopicsCount}}
|
||||
@bulkSelectHelper={{@bulkSelectHelper}}
|
||||
@changeNewListSubset={{@changeNewListSubset}}
|
||||
/>
|
||||
{{/each}}
|
||||
</tr>
|
||||
|
||||
@@ -3,7 +3,6 @@ import { on } from "@ember/modifier";
|
||||
import { action } from "@ember/object";
|
||||
import { service } from "@ember/service";
|
||||
import PluginOutlet from "discourse/components/plugin-outlet";
|
||||
import NewListHeaderControls from "discourse/components/topic-list/new-list-header-controls";
|
||||
import TopicBulkSelectDropdown from "discourse/components/topic-list/topic-bulk-select-dropdown";
|
||||
import concatClass from "discourse/helpers/concat-class";
|
||||
import icon from "discourse/helpers/d-icon";
|
||||
@@ -116,14 +115,6 @@ export default class SortableColumn extends Component {
|
||||
{{/if}}
|
||||
|
||||
{{#unless @bulkSelectEnabled}}
|
||||
{{#if @showTopicsAndRepliesToggle}}
|
||||
<NewListHeaderControls
|
||||
@current={{@newListSubset}}
|
||||
@newRepliesCount={{@newRepliesCount}}
|
||||
@newTopicsCount={{@newTopicsCount}}
|
||||
@changeNewListSubset={{@changeNewListSubset}}
|
||||
/>
|
||||
{{else}}
|
||||
{{#if @sortable}}
|
||||
<button aria-pressed={{this.isSorting}}>
|
||||
{{this.localizedName}}
|
||||
@@ -136,7 +127,6 @@ export default class SortableColumn extends Component {
|
||||
{{this.localizedName}}
|
||||
</span>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/unless}}
|
||||
|
||||
<PluginOutlet
|
||||
|
||||
@@ -12,12 +12,7 @@ const TopicCell = <template>
|
||||
@showBulkToggle={{@showBulkToggle}}
|
||||
@canBulkSelect={{@canBulkSelect}}
|
||||
@canDoBulkActions={{@canDoBulkActions}}
|
||||
@showTopicsAndRepliesToggle={{@showTopicsAndRepliesToggle}}
|
||||
@newListSubset={{@newListSubset}}
|
||||
@newRepliesCount={{@newRepliesCount}}
|
||||
@newTopicsCount={{@newTopicsCount}}
|
||||
@bulkSelectHelper={{@bulkSelectHelper}}
|
||||
@changeNewListSubset={{@changeNewListSubset}}
|
||||
/>
|
||||
</template>;
|
||||
|
||||
|
||||
@@ -208,11 +208,6 @@ export default class TopicList extends Component {
|
||||
@bulkSelectHelper={{@bulkSelectHelper}}
|
||||
@bulkSelectEnabled={{this.bulkSelectEnabled}}
|
||||
@canDoBulkActions={{this.canDoBulkActions}}
|
||||
@showTopicsAndRepliesToggle={{@showTopicsAndRepliesToggle}}
|
||||
@newListSubset={{@newListSubset}}
|
||||
@newRepliesCount={{@newRepliesCount}}
|
||||
@newTopicsCount={{@newTopicsCount}}
|
||||
@changeNewListSubset={{@changeNewListSubset}}
|
||||
/>
|
||||
</thead>
|
||||
|
||||
|
||||
-19
@@ -37,25 +37,7 @@ export default class NewListHeaderControls extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
get staticLabel() {
|
||||
if (
|
||||
this.args.noStaticLabel ||
|
||||
(this.args.newTopicsCount > 0 && this.args.newRepliesCount > 0)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.args.newTopicsCount > 0) {
|
||||
return this.topicsButtonLabel;
|
||||
} else {
|
||||
return this.repliesButtonLabel;
|
||||
}
|
||||
}
|
||||
|
||||
<template>
|
||||
{{#if this.staticLabel}}
|
||||
<span class="static-label">{{this.staticLabel}}</span>
|
||||
{{else}}
|
||||
<button
|
||||
{{on "click" (fn @changeNewListSubset null)}}
|
||||
class={{concatClass
|
||||
@@ -88,6 +70,5 @@ export default class NewListHeaderControls extends Component {
|
||||
>
|
||||
{{this.repliesButtonLabel}}
|
||||
</button>
|
||||
{{/if}}
|
||||
</template>
|
||||
}
|
||||
|
||||
@@ -77,19 +77,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.topics-replies-toggle {
|
||||
background: none;
|
||||
border: none;
|
||||
line-height: var(--line-height-large);
|
||||
padding-left: var(--space-2);
|
||||
padding-right: var(--space-2);
|
||||
position: relative;
|
||||
|
||||
&.active {
|
||||
@include nav-active;
|
||||
}
|
||||
}
|
||||
|
||||
$td-posters-height: 29px; // min-height of td with avatar glow
|
||||
$td-posters-more-lh: $td-posters-height - 4;
|
||||
|
||||
@@ -291,6 +278,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
.topic-replies-toggle-wrapper {
|
||||
.topics-replies-toggle {
|
||||
background: none;
|
||||
border: none;
|
||||
line-height: var(--line-height-large);
|
||||
padding: var(--space-2);
|
||||
position: relative;
|
||||
|
||||
&.active {
|
||||
@include nav-active;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include viewport.until(lg) {
|
||||
.nav-pills {
|
||||
> li > a {
|
||||
|
||||
@@ -3701,6 +3701,8 @@ en:
|
||||
browse_all_categories_latest_or_top: "<a href='%{basePath}/categories'>Browse all categories</a>, <a href='%{basePath}/latest'>view latest topics</a> or see top:"
|
||||
browse_all_tags_or_latest: "<a href='%{basePath}/tags'>Browse all tags</a> or <a href='%{basePath}/latest'>view latest topics</a>."
|
||||
browse_latest_topics: "Browse latest topics"
|
||||
browse_new_replies: "Browse new replies"
|
||||
browse_new_topics: "Browse new topics"
|
||||
|
||||
suggest_create_topic: Ready to <a href>start a new conversation?</a>
|
||||
jump_reply: "Jump to post's original location"
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module PageObjects
|
||||
module Components
|
||||
class EmptyState < PageObjects::Components::Base
|
||||
def has_cta_text?(text)
|
||||
has_css?(".empty-state__cta", text: text)
|
||||
end
|
||||
|
||||
def click_cta
|
||||
find(".empty-state__cta").click
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -13,6 +13,10 @@ module PageObjects
|
||||
has_no_css?(COMMON_SELECTOR)
|
||||
end
|
||||
|
||||
def rendered?
|
||||
has_css?(COMMON_SELECTOR)
|
||||
end
|
||||
|
||||
def all_tab
|
||||
@all_tab ||= PageObjects::Components::NewTopicListToggleTab.new("all", ALL_SELECTOR)
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe "New topic list", type: :system do
|
||||
describe "Unified new topic list", type: :system do
|
||||
fab!(:user)
|
||||
fab!(:group) { Fabricate(:group, users: [user]) }
|
||||
fab!(:category)
|
||||
@@ -26,11 +26,12 @@ describe "New topic list", type: :system do
|
||||
|
||||
let(:topic_list) { PageObjects::Components::TopicList.new }
|
||||
let(:tabs_toggle) { PageObjects::Components::NewTopicListToggle.new }
|
||||
let(:empty_state) { PageObjects::Components::EmptyState.new }
|
||||
|
||||
before { sign_in(user) }
|
||||
|
||||
shared_examples "new list new topics and replies toggle" do
|
||||
context "when the new new view is enabled" do
|
||||
context "when unified new is enabled" do
|
||||
before { SiteSetting.experimental_new_new_view_groups = group.name }
|
||||
|
||||
it "shows all new topics and replies by default" do
|
||||
@@ -302,7 +303,7 @@ describe "New topic list", type: :system do
|
||||
end
|
||||
end
|
||||
|
||||
context "when the new new view is not enabled" do
|
||||
context "when unified new is not enabled" do
|
||||
before { SiteSetting.experimental_new_new_view_groups = "" }
|
||||
|
||||
it "doesn't show the tabs toggle" do
|
||||
@@ -324,15 +325,23 @@ describe "New topic list", type: :system do
|
||||
end
|
||||
end
|
||||
|
||||
it "keeps the Topics tab even when there are no new topics" do
|
||||
it "shows All, Topics, and Replies tabs" do
|
||||
visit("/new")
|
||||
|
||||
expect(tabs_toggle).to be_rendered
|
||||
expect(tabs_toggle.all_tab).to be_visible
|
||||
expect(tabs_toggle.replies_tab).to be_visible
|
||||
expect(tabs_toggle.topics_tab).to be_visible
|
||||
end
|
||||
|
||||
expect(tabs_toggle.replies_tab).to have_count(3)
|
||||
expect(tabs_toggle.topics_tab).to have_count(0)
|
||||
it "shows a CTA to show replies when on the new topics tab" do
|
||||
visit("/new?subset=topics")
|
||||
|
||||
expect(empty_state).to have_cta_text(I18n.t("js.topic.browse_new_replies"))
|
||||
empty_state.click_cta
|
||||
|
||||
expect(tabs_toggle.replies_tab).to be_active
|
||||
expect(page).to have_current_path("/new?subset=replies")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -345,15 +354,23 @@ describe "New topic list", type: :system do
|
||||
end
|
||||
end
|
||||
|
||||
it "keeps the Replies tab even when there are no new replies" do
|
||||
it "shows All, Topics, and Replies tabs" do
|
||||
visit("/new")
|
||||
|
||||
expect(tabs_toggle).to be_rendered
|
||||
expect(tabs_toggle.all_tab).to be_visible
|
||||
expect(tabs_toggle.replies_tab).to be_visible
|
||||
expect(tabs_toggle.topics_tab).to be_visible
|
||||
end
|
||||
|
||||
expect(tabs_toggle.replies_tab).to have_count(0)
|
||||
expect(tabs_toggle.topics_tab).to have_count(3)
|
||||
it "shows a CTA to show topics when on the new replies tab" do
|
||||
visit("/new?subset=replies")
|
||||
|
||||
expect(empty_state).to have_cta_text(I18n.t("js.topic.browse_new_topics"))
|
||||
empty_state.click_cta
|
||||
|
||||
expect(tabs_toggle.topics_tab).to be_active
|
||||
expect(page).to have_current_path("/new?subset=topics")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -370,13 +387,23 @@ describe "New topic list", type: :system do
|
||||
end
|
||||
end
|
||||
|
||||
it "doesn't render the toggle and only shows a static label for new topics" do
|
||||
it "shows All, Topics, and Replies tabs" do
|
||||
visit("/new")
|
||||
|
||||
expect(tabs_toggle).to be_not_rendered
|
||||
expect(find(".topic-list-header .static-label").text).to eq(
|
||||
I18n.t("js.filters.new.topics_with_count", count: 3),
|
||||
)
|
||||
expect(tabs_toggle).to be_rendered
|
||||
expect(tabs_toggle.all_tab).to be_visible
|
||||
expect(tabs_toggle.replies_tab).to be_visible
|
||||
expect(tabs_toggle.topics_tab).to be_visible
|
||||
end
|
||||
|
||||
it "shows a CTA to show topics when on the new replies tab" do
|
||||
visit("/new?subset=replies")
|
||||
|
||||
expect(empty_state).to have_cta_text(I18n.t("js.topic.browse_new_topics"))
|
||||
empty_state.click_cta
|
||||
|
||||
expect(tabs_toggle.topics_tab).to be_active
|
||||
expect(page).to have_current_path("/new?subset=topics")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -389,13 +416,23 @@ describe "New topic list", type: :system do
|
||||
end
|
||||
end
|
||||
|
||||
it "doesn't render the toggle and only shows a static label for new replies" do
|
||||
it "shows All, Topics, and Replies tabs" do
|
||||
visit("/new")
|
||||
|
||||
expect(tabs_toggle).to be_not_rendered
|
||||
expect(find(".topic-list-header .static-label").text).to eq(
|
||||
I18n.t("js.filters.new.replies_with_count", count: 3),
|
||||
)
|
||||
expect(tabs_toggle).to be_rendered
|
||||
expect(tabs_toggle.all_tab).to be_visible
|
||||
expect(tabs_toggle.replies_tab).to be_visible
|
||||
expect(tabs_toggle.topics_tab).to be_visible
|
||||
end
|
||||
|
||||
it "shows a CTA to show replies when on the new topics tab" do
|
||||
visit("/new?subset=topics")
|
||||
|
||||
expect(empty_state).to have_cta_text(I18n.t("js.topic.browse_new_replies"))
|
||||
empty_state.click_cta
|
||||
|
||||
expect(tabs_toggle.replies_tab).to be_active
|
||||
expect(page).to have_current_path("/new?subset=replies")
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user