mirror of
https://github.com/discourse/discourse.git
synced 2024-11-22 11:23:25 +08:00
FEATURE: New topics vs replies toggle for the new new view (#22920)
This PR adds a new toggle to switch the (new) /new list between showing topics with new replies (a.k.a unread topics), new topics, or everything mixed together.
This commit is contained in:
parent
79e3d4e2bd
commit
09d3709ec9
|
@ -0,0 +1,13 @@
|
|||
<div
|
||||
class="topic-replies-toggle-wrapper"
|
||||
{{on "click" (action this.click)}}
|
||||
{{! template-lint-disable no-invalid-interactive }}
|
||||
>
|
||||
{{raw
|
||||
"list/new-list-header-controls"
|
||||
current=@current
|
||||
newRepliesCount=@newRepliesCount
|
||||
newTopicsCount=@newTopicsCount
|
||||
noStaticLabel=true
|
||||
}}
|
||||
</div>
|
|
@ -0,0 +1,14 @@
|
|||
import Component from "@glimmer/component";
|
||||
|
||||
export default class NewListHeaderControlsWrapper extends Component {
|
||||
click(e) {
|
||||
const target = e.target;
|
||||
if (target.closest("button.topics-replies-toggle.all")) {
|
||||
this.args.changeNewListSubset(null);
|
||||
} else if (target.closest("button.topics-replies-toggle.topics")) {
|
||||
this.args.changeNewListSubset("topics");
|
||||
} else if (target.closest("button.topics-replies-toggle.replies")) {
|
||||
this.args.changeNewListSubset("replies");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,6 +13,10 @@
|
|||
listTitle=this.listTitle
|
||||
bulkSelectEnabled=this.bulkSelectEnabled
|
||||
canDoBulkActions=this.canDoBulkActions
|
||||
showTopicsAndRepliesToggle=this.showTopicsAndRepliesToggle
|
||||
newListSubset=this.newListSubset
|
||||
newRepliesCount=this.newRepliesCount
|
||||
newTopicsCount=this.newTopicsCount
|
||||
}}
|
||||
</thead>
|
||||
|
||||
|
|
|
@ -184,6 +184,17 @@ export default Component.extend(LoadMore, {
|
|||
},
|
||||
});
|
||||
});
|
||||
|
||||
onClick("button.topics-replies-toggle", (element) => {
|
||||
if (element.classList.contains("all")) {
|
||||
this.changeNewListSubset(null);
|
||||
} else if (element.classList.contains("topics")) {
|
||||
this.changeNewListSubset("topics");
|
||||
} else if (element.classList.contains("replies")) {
|
||||
this.changeNewListSubset("replies");
|
||||
}
|
||||
this.rerender();
|
||||
});
|
||||
},
|
||||
|
||||
keyDown(e) {
|
||||
|
|
|
@ -13,6 +13,7 @@ export const queryParams = {
|
|||
before: { replace: true, refreshModel: true },
|
||||
bumped_before: { replace: true, refreshModel: true },
|
||||
f: { replace: true, refreshModel: true },
|
||||
subset: { replace: true, refreshModel: true },
|
||||
period: { replace: true, refreshModel: true },
|
||||
topic_ids: { replace: true, refreshModel: true },
|
||||
group_name: { replace: true, refreshModel: true },
|
||||
|
@ -35,6 +36,13 @@ export function changeSort(sortBy) {
|
|||
}
|
||||
}
|
||||
|
||||
export function changeNewListSubset(subset) {
|
||||
this.controller.set("subset", subset);
|
||||
|
||||
let model = this.controllerFor("discovery.topics").model;
|
||||
model.updateNewListSubsetParam(subset);
|
||||
}
|
||||
|
||||
export function resetParams(skipParams = []) {
|
||||
Object.keys(queryParams).forEach((p) => {
|
||||
if (!skipParams.includes(p)) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { inject as controller } from "@ember/controller";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { alias, empty, equal, gt, not, readOnly } from "@ember/object/computed";
|
||||
import { alias, empty, equal, gt, readOnly } from "@ember/object/computed";
|
||||
import BulkTopicSelection from "discourse/mixins/bulk-topic-selection";
|
||||
import DismissTopics from "discourse/mixins/dismiss-topics";
|
||||
import DiscoveryController from "discourse/controllers/discovery";
|
||||
|
@ -27,7 +27,6 @@ export default class TopicsController extends DiscoveryController.extend(
|
|||
expandAllPinned = false;
|
||||
|
||||
@alias("currentUser.id") canStar;
|
||||
@not("new") showTopicPostBadges;
|
||||
@alias("currentUser.user_option.redirected_to_top.reason") redirectedReason;
|
||||
@readOnly("model.params.order") order;
|
||||
@readOnly("model.params.ascending") ascending;
|
||||
|
@ -119,7 +118,41 @@ export default class TopicsController extends DiscoveryController.extend(
|
|||
|
||||
@discourseComputed("model.filter")
|
||||
new(filter) {
|
||||
return filter?.endsWith("new") && !this.currentUser?.new_new_view_enabled;
|
||||
return filter?.endsWith("new");
|
||||
}
|
||||
|
||||
@discourseComputed("new")
|
||||
showTopicsAndRepliesToggle(isNew) {
|
||||
return isNew && this.currentUser?.new_new_view_enabled;
|
||||
}
|
||||
|
||||
@discourseComputed("topicTrackingState.messageCount")
|
||||
newRepliesCount() {
|
||||
if (this.currentUser?.new_new_view_enabled) {
|
||||
return this.topicTrackingState.countUnread({
|
||||
categoryId: this.category?.id,
|
||||
noSubcategories: this.noSubcategories,
|
||||
});
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@discourseComputed("topicTrackingState.messageCount")
|
||||
newTopicsCount() {
|
||||
if (this.currentUser?.new_new_view_enabled) {
|
||||
return this.topicTrackingState.countNew({
|
||||
categoryId: this.category?.id,
|
||||
noSubcategories: this.noSubcategories,
|
||||
});
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@discourseComputed("new")
|
||||
showTopicPostBadges(isNew) {
|
||||
return !isNew || this.currentUser?.new_new_view_enabled;
|
||||
}
|
||||
|
||||
@discourseComputed("allLoaded", "model.topics.length")
|
||||
|
|
|
@ -101,9 +101,45 @@ export default class TagShowController extends DiscoverySortableController.exten
|
|||
return this._isFilterPage(filter, "unread") && topicsLength > 0;
|
||||
}
|
||||
|
||||
@discourseComputed("list.filter", "list.topics.length")
|
||||
showResetNew(filter, topicsLength) {
|
||||
return this._isFilterPage(filter, "new") && topicsLength > 0;
|
||||
@discourseComputed("list.filter")
|
||||
new(filter) {
|
||||
return this._isFilterPage(filter, "new");
|
||||
}
|
||||
|
||||
@discourseComputed("new")
|
||||
showTopicsAndRepliesToggle(isNew) {
|
||||
return isNew && this.currentUser?.new_new_view_enabled;
|
||||
}
|
||||
|
||||
@discourseComputed("topicTrackingState.messageCount")
|
||||
newRepliesCount() {
|
||||
if (this.currentUser?.new_new_view_enabled) {
|
||||
return this.topicTrackingState.countUnread({
|
||||
categoryId: this.category?.id,
|
||||
noSubcategories: this.noSubcategories,
|
||||
tagId: this.tag?.id,
|
||||
});
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@discourseComputed("topicTrackingState.messageCount")
|
||||
newTopicsCount() {
|
||||
if (this.currentUser?.new_new_view_enabled) {
|
||||
return this.topicTrackingState.countNew({
|
||||
categoryId: this.category?.id,
|
||||
noSubcategories: this.noSubcategories,
|
||||
tagId: this.tag?.id,
|
||||
});
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@discourseComputed("new", "list.topics.length")
|
||||
showResetNew(isNew, topicsLength) {
|
||||
return isNew && topicsLength > 0;
|
||||
}
|
||||
|
||||
callResetNew(dismissPosts = false, dismissTopics = false, untrack = false) {
|
||||
|
@ -148,6 +184,11 @@ export default class TagShowController extends DiscoverySortableController.exten
|
|||
}
|
||||
}
|
||||
|
||||
@action
|
||||
changeNewListSubset(subset) {
|
||||
this.set("subset", subset);
|
||||
}
|
||||
|
||||
@action
|
||||
changePeriod(p) {
|
||||
this.set("period", p);
|
||||
|
|
|
@ -67,6 +67,18 @@ const TopicList = RestModel.extend({
|
|||
this.set("params", params);
|
||||
},
|
||||
|
||||
updateNewListSubsetParam(subset) {
|
||||
let params = Object.assign({}, this.params || {});
|
||||
|
||||
if (params.q) {
|
||||
params = { q: params.q };
|
||||
} else {
|
||||
params.subset = subset;
|
||||
}
|
||||
|
||||
this.set("params", params);
|
||||
},
|
||||
|
||||
loadMore() {
|
||||
if (this.loadingMore) {
|
||||
return Promise.resolve();
|
||||
|
|
|
@ -94,45 +94,45 @@ const TopicTrackingState = EmberObject.extend({
|
|||
this.messageBus.subscribe(
|
||||
"/latest",
|
||||
this._processChannelPayload,
|
||||
meta["/latest"] || messageBusDefaultNewMessageId
|
||||
meta["/latest"] ?? messageBusDefaultNewMessageId
|
||||
);
|
||||
|
||||
if (this.currentUser) {
|
||||
this.messageBus.subscribe(
|
||||
"/new",
|
||||
this._processChannelPayload,
|
||||
meta["/new"] || messageBusDefaultNewMessageId
|
||||
meta["/new"] ?? messageBusDefaultNewMessageId
|
||||
);
|
||||
|
||||
this.messageBus.subscribe(
|
||||
`/unread`,
|
||||
this._processChannelPayload,
|
||||
meta["/unread"] || messageBusDefaultNewMessageId
|
||||
meta["/unread"] ?? messageBusDefaultNewMessageId
|
||||
);
|
||||
|
||||
this.messageBus.subscribe(
|
||||
`/unread/${this.currentUser.id}`,
|
||||
this._processChannelPayload,
|
||||
meta[`/unread/${this.currentUser.id}`] || messageBusDefaultNewMessageId
|
||||
meta[`/unread/${this.currentUser.id}`] ?? messageBusDefaultNewMessageId
|
||||
);
|
||||
}
|
||||
|
||||
this.messageBus.subscribe(
|
||||
"/delete",
|
||||
this.onDeleteMessage,
|
||||
meta["/delete"] || messageBusDefaultNewMessageId
|
||||
meta["/delete"] ?? messageBusDefaultNewMessageId
|
||||
);
|
||||
|
||||
this.messageBus.subscribe(
|
||||
"/recover",
|
||||
this.onRecoverMessage,
|
||||
meta["/recover"] || messageBusDefaultNewMessageId
|
||||
meta["/recover"] ?? messageBusDefaultNewMessageId
|
||||
);
|
||||
|
||||
this.messageBus.subscribe(
|
||||
"/destroy",
|
||||
this.onDestroyMessage,
|
||||
meta["/destroy"] || messageBusDefaultNewMessageId
|
||||
meta["/destroy"] ?? messageBusDefaultNewMessageId
|
||||
);
|
||||
},
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
{{#if view.staticLabel}}
|
||||
<span class="static-label">{{view.staticLabel}}</span>
|
||||
{{else}}
|
||||
<button class="topics-replies-toggle all{{#if view.allActive}} active{{/if}}">
|
||||
{{view.allButtonLabel}}
|
||||
</button>
|
||||
<button class="topics-replies-toggle topics{{#if view.topicsActive}} active{{/if}}">
|
||||
{{view.topicsButtonLabel}}
|
||||
</button>
|
||||
<button class="topics-replies-toggle replies{{#if view.repliesActive}} active{{/if}}">
|
||||
{{view.repliesButtonLabel}}
|
||||
</button>
|
||||
{{/if}}
|
|
@ -13,7 +13,11 @@
|
|||
</span>
|
||||
{{/if ~}}
|
||||
{{/if ~}}
|
||||
<span>{{view.localizedName}}</span>
|
||||
{{~#if view.showTopicsAndRepliesToggle}}
|
||||
{{raw "list/new-list-header-controls" current=newListSubset newRepliesCount=newRepliesCount newTopicsCount=newTopicsCount}}
|
||||
{{else}}
|
||||
<span>{{view.localizedName}}</span>
|
||||
{{/if ~}}
|
||||
{{~#if view.isSorting}}
|
||||
{{d-icon view.sortIcon}}
|
||||
{{/if ~}}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
{{/if}}
|
||||
</th>
|
||||
{{/if}}
|
||||
{{raw "topic-list-header-column" order='default' name=listTitle bulkSelectEnabled=bulkSelectEnabled showBulkToggle=toggleInTitle canBulkSelect=canBulkSelect canDoBulkActions=canDoBulkActions}}
|
||||
{{raw "topic-list-header-column" order='default' name=listTitle bulkSelectEnabled=bulkSelectEnabled showBulkToggle=toggleInTitle canBulkSelect=canBulkSelect canDoBulkActions=canDoBulkActions showTopicsAndRepliesToggle=showTopicsAndRepliesToggle newListSubset=newListSubset newRepliesCount=newRepliesCount newTopicsCount=newTopicsCount}}
|
||||
{{raw-plugin-outlet name="topic-list-header-after-main-link"}}
|
||||
{{#if showPosters}}
|
||||
{{raw "topic-list-header-column" order='posters' ariaLabel=(i18n "category.sort_options.posters")}}
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
import EmberObject from "@ember/object";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default EmberObject.extend({
|
||||
@discourseComputed
|
||||
topicsActive() {
|
||||
return this.current === "topics";
|
||||
},
|
||||
|
||||
@discourseComputed
|
||||
repliesActive() {
|
||||
return this.current === "replies";
|
||||
},
|
||||
|
||||
@discourseComputed
|
||||
allActive() {
|
||||
return !this.topicsActive && !this.repliesActive;
|
||||
},
|
||||
|
||||
@discourseComputed
|
||||
allButtonLabel() {
|
||||
const count = this.newRepliesCount + this.newTopicsCount;
|
||||
if (count > 0) {
|
||||
return I18n.t("filters.new.all_with_count", { count });
|
||||
} else {
|
||||
return I18n.t("filters.new.all");
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed
|
||||
repliesButtonLabel() {
|
||||
if (this.newRepliesCount > 0) {
|
||||
return I18n.t("filters.new.replies_with_count", {
|
||||
count: this.newRepliesCount,
|
||||
});
|
||||
} else {
|
||||
return I18n.t("filters.new.replies");
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed
|
||||
topicsButtonLabel() {
|
||||
if (this.newTopicsCount > 0) {
|
||||
return I18n.t("filters.new.topics_with_count", {
|
||||
count: this.newTopicsCount,
|
||||
});
|
||||
} else {
|
||||
return I18n.t("filters.new.topics");
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed
|
||||
staticLabel() {
|
||||
if (this.noStaticLabel) {
|
||||
return null;
|
||||
}
|
||||
if (this.newTopicsCount > 0 && this.newRepliesCount > 0) {
|
||||
return null;
|
||||
}
|
||||
if (this.newTopicsCount > 0) {
|
||||
return this.topicsButtonLabel;
|
||||
} else {
|
||||
return this.repliesButtonLabel;
|
||||
}
|
||||
},
|
||||
});
|
|
@ -1,6 +1,7 @@
|
|||
import { inject as service } from "@ember/service";
|
||||
import { Promise, all } from "rsvp";
|
||||
import {
|
||||
changeNewListSubset,
|
||||
changeSort,
|
||||
queryParams,
|
||||
resetParams,
|
||||
|
@ -218,6 +219,11 @@ class AbstractCategoryRoute extends DiscourseRoute {
|
|||
changeSort.call(this, sortBy);
|
||||
}
|
||||
|
||||
@action
|
||||
changeNewListSubset(subset) {
|
||||
changeNewListSubset.call(this, subset);
|
||||
}
|
||||
|
||||
@action
|
||||
resetParams(skipParams = []) {
|
||||
resetParams.call(this, skipParams);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import {
|
||||
changeNewListSubset,
|
||||
changeSort,
|
||||
queryParams,
|
||||
resetParams,
|
||||
|
@ -165,6 +166,11 @@ class AbstractTopicRoute extends DiscourseRoute {
|
|||
changeSort.call(this, sortBy);
|
||||
}
|
||||
|
||||
@action
|
||||
changeNewListSubset(subset) {
|
||||
changeNewListSubset.call(this, subset);
|
||||
}
|
||||
|
||||
@action
|
||||
resetParams(skipParams = []) {
|
||||
resetParams.call(this, skipParams);
|
||||
|
|
|
@ -37,8 +37,11 @@ export default class DiscoveryFilterRoute extends DiscourseRoute {
|
|||
});
|
||||
}
|
||||
|
||||
// TODO(tgxworld): This action is required by the `discovery/topics` controller which is not necessary for this route.
|
||||
// TODO(tgxworld): The following 2 actions are required by the `discovery/topics` controller which is not necessary for this route.
|
||||
// Figure out a way to remove this.
|
||||
@action
|
||||
changeSort() {}
|
||||
|
||||
@action
|
||||
changeNewListSubset() {}
|
||||
}
|
||||
|
|
|
@ -94,9 +94,13 @@
|
|||
@topics={{this.model.topics}}
|
||||
@discoveryList={{true}}
|
||||
@focusLastVisitedTopic={{true}}
|
||||
@showTopicsAndRepliesToggle={{this.showTopicsAndRepliesToggle}}
|
||||
@newListSubset={{this.model.params.subset}}
|
||||
@changeNewListSubset={{route-action "changeNewListSubset"}}
|
||||
@newRepliesCount={{this.newRepliesCount}}
|
||||
@newTopicsCount={{this.newTopicsCount}}
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
<span>
|
||||
<PluginOutlet
|
||||
@name="after-topic-list"
|
||||
|
|
|
@ -40,6 +40,14 @@
|
|||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#if this.showTopicsAndRepliesToggle}}
|
||||
<NewListHeaderControlsWrapper
|
||||
@current={{this.model.params.subset}}
|
||||
@newRepliesCount={{this.newRepliesCount}}
|
||||
@newTopicsCount={{this.newTopicsCount}}
|
||||
@changeNewListSubset={{route-action "changeNewListSubset"}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{#if this.hasTopics}}
|
||||
<TopicList
|
||||
@ascending={{this.ascending}}
|
||||
|
|
|
@ -127,6 +127,14 @@
|
|||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#if (and this.showTopicsAndRepliesToggle this.site.mobileView)}}
|
||||
<NewListHeaderControlsWrapper
|
||||
@current={{this.subset}}
|
||||
@newRepliesCount={{this.newRepliesCount}}
|
||||
@newTopicsCount={{this.newTopicsCount}}
|
||||
@changeNewListSubset={{action "changeNewListSubset"}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{#if this.list.topics}}
|
||||
<TopicList
|
||||
@topics={{this.list.topics}}
|
||||
|
@ -144,6 +152,11 @@
|
|||
@ascending={{this.ascending}}
|
||||
@changeSort={{action "changeSort"}}
|
||||
@focusLastVisitedTopic={{true}}
|
||||
@showTopicsAndRepliesToggle={{this.showTopicsAndRepliesToggle}}
|
||||
@newListSubset={{this.subset}}
|
||||
@changeNewListSubset={{action "changeNewListSubset"}}
|
||||
@newRepliesCount={{this.newRepliesCount}}
|
||||
@newTopicsCount={{this.newTopicsCount}}
|
||||
/>
|
||||
{{/if}}
|
||||
</DiscoveryTopicsList>
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
&:last-of-type {
|
||||
padding-right: 10px;
|
||||
}
|
||||
th & {
|
||||
border-bottom: 3px solid var(--primary-low);
|
||||
}
|
||||
}
|
||||
|
||||
button.bulk-select {
|
||||
|
@ -52,6 +55,18 @@
|
|||
}
|
||||
}
|
||||
|
||||
.topics-replies-toggle {
|
||||
background: none;
|
||||
border: none;
|
||||
line-height: var(--line-height-large);
|
||||
min-height: 30px;
|
||||
|
||||
&.active {
|
||||
background: var(--quaternary);
|
||||
color: var(--secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.badge-notification {
|
||||
position: relative;
|
||||
top: -2px;
|
||||
|
|
|
@ -569,3 +569,22 @@ td .main-link {
|
|||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.topic-replies-toggle-wrapper {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.topics-replies-toggle {
|
||||
flex-grow: 1;
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0.75em;
|
||||
box-shadow: 0 3px 0 var(--primary-low);
|
||||
|
||||
&.active {
|
||||
color: var(--quaternary);
|
||||
box-shadow: 0 3px 0 var(--quaternary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3995,6 +3995,12 @@ en:
|
|||
one: "New (%{count})"
|
||||
other: "New (%{count})"
|
||||
help: "topics created in the last few days"
|
||||
all: "All"
|
||||
all_with_count: "All (%{count})"
|
||||
topics: "Topics"
|
||||
topics_with_count: "Topics (%{count})"
|
||||
replies: "Replies"
|
||||
replies_with_count: "Replies (%{count})"
|
||||
posted:
|
||||
title: "My Posts"
|
||||
help: "topics you have posted in"
|
||||
|
|
|
@ -53,6 +53,7 @@ class TopicQuery
|
|||
search
|
||||
q
|
||||
f
|
||||
subset
|
||||
group_name
|
||||
tags
|
||||
match_all_tags
|
||||
|
@ -304,7 +305,16 @@ class TopicQuery
|
|||
|
||||
def list_new
|
||||
if @user&.new_new_view_enabled?
|
||||
create_list(:new, { unordered: true }, new_and_unread_results)
|
||||
list =
|
||||
case @options[:subset]
|
||||
when "topics"
|
||||
new_results
|
||||
when "replies"
|
||||
unread_results
|
||||
else
|
||||
new_and_unread_results
|
||||
end
|
||||
create_list(:new, { unordered: true }, list)
|
||||
else
|
||||
create_list(:new, { unordered: true }, new_results)
|
||||
end
|
||||
|
|
|
@ -1410,4 +1410,150 @@ RSpec.describe ListController do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#new" do
|
||||
def extract_topic_ids(response)
|
||||
response.parsed_body["topic_list"]["topics"].map { |topics| topics["id"] }
|
||||
end
|
||||
|
||||
def make_topic_with_unread_replies(topic, user)
|
||||
TopicUser.change(
|
||||
user.id,
|
||||
topic.id,
|
||||
notification_level: TopicUser.notification_levels[:tracking],
|
||||
)
|
||||
TopicUser.update_last_read(user, topic.id, 1, 1, 1)
|
||||
Fabricate(:post, topic: topic)
|
||||
topic
|
||||
end
|
||||
|
||||
def make_topic_read(topic, user)
|
||||
TopicUser.update_last_read(user, topic.id, 1, 1, 1)
|
||||
topic
|
||||
end
|
||||
|
||||
context "when the user is part of the `experimental_new_new_view_groups` site setting group" do
|
||||
fab!(:category) { Fabricate(:category) }
|
||||
fab!(:tag) { Fabricate(:tag) }
|
||||
|
||||
fab!(:new_reply) { make_topic_with_unread_replies(Fabricate(:post).topic, user) }
|
||||
fab!(:new_topic) { Fabricate(:post).topic }
|
||||
fab!(:old_topic) { make_topic_read(Fabricate(:post).topic, user) }
|
||||
|
||||
fab!(:new_reply_in_category) do
|
||||
make_topic_with_unread_replies(
|
||||
Fabricate(:post, topic: Fabricate(:topic, category: category)).topic,
|
||||
user,
|
||||
)
|
||||
end
|
||||
fab!(:new_topic_in_category) do
|
||||
Fabricate(:post, topic: Fabricate(:topic, category: category)).topic
|
||||
end
|
||||
fab!(:old_topic_in_category) do
|
||||
make_topic_read(Fabricate(:post, topic: Fabricate(:topic, category: category)).topic, user)
|
||||
end
|
||||
|
||||
fab!(:new_reply_with_tag) do
|
||||
make_topic_with_unread_replies(
|
||||
Fabricate(:post, topic: Fabricate(:topic, tags: [tag])).topic,
|
||||
user,
|
||||
)
|
||||
end
|
||||
fab!(:new_topic_with_tag) { Fabricate(:post, topic: Fabricate(:topic, tags: [tag])).topic }
|
||||
fab!(:old_topic_with_tag) do
|
||||
make_topic_read(Fabricate(:post, topic: Fabricate(:topic, tags: [tag])).topic, user)
|
||||
end
|
||||
|
||||
before do
|
||||
make_topic_read(topic, user)
|
||||
|
||||
SiteSetting.experimental_new_new_view_groups = group.name
|
||||
group.add(user)
|
||||
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
it "returns new topics and topics with new replies" do
|
||||
get "/new.json"
|
||||
|
||||
ids = extract_topic_ids(response)
|
||||
expect(ids).to contain_exactly(
|
||||
new_reply.id,
|
||||
new_topic.id,
|
||||
new_reply_in_category.id,
|
||||
new_topic_in_category.id,
|
||||
new_reply_with_tag.id,
|
||||
new_topic_with_tag.id,
|
||||
)
|
||||
end
|
||||
|
||||
context "when the subset param is set to topics" do
|
||||
it "returns only new topics" do
|
||||
get "/new.json", params: { subset: "topics" }
|
||||
|
||||
ids = extract_topic_ids(response)
|
||||
expect(ids).to contain_exactly(
|
||||
new_topic.id,
|
||||
new_topic_in_category.id,
|
||||
new_topic_with_tag.id,
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when the subset param is set to replies" do
|
||||
it "returns only topics with new replies" do
|
||||
get "/new.json", params: { subset: "replies" }
|
||||
|
||||
ids = extract_topic_ids(response)
|
||||
expect(ids).to contain_exactly(
|
||||
new_reply.id,
|
||||
new_reply_in_category.id,
|
||||
new_reply_with_tag.id,
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when filtering the list to a specific category" do
|
||||
it "returns new topics in that category" do
|
||||
get "/c/#{category.slug}/#{category.id}/l/new.json"
|
||||
|
||||
ids = extract_topic_ids(response)
|
||||
expect(ids).to contain_exactly(new_topic_in_category.id, new_reply_in_category.id)
|
||||
end
|
||||
|
||||
it "respects the subset param" do
|
||||
get "/c/#{category.slug}/#{category.id}/l/new.json", params: { subset: "topics" }
|
||||
|
||||
ids = extract_topic_ids(response)
|
||||
expect(ids).to contain_exactly(new_topic_in_category.id)
|
||||
|
||||
get "/c/#{category.slug}/#{category.id}/l/new.json", params: { subset: "replies" }
|
||||
|
||||
ids = extract_topic_ids(response)
|
||||
expect(ids).to contain_exactly(new_reply_in_category.id)
|
||||
end
|
||||
end
|
||||
|
||||
context "when filtering the list to topics with a specific tag" do
|
||||
it "returns new topics with the specified tag" do
|
||||
get "/tag/#{tag.name}/l/new.json"
|
||||
|
||||
ids = extract_topic_ids(response)
|
||||
expect(ids).to contain_exactly(new_topic_with_tag.id, new_reply_with_tag.id)
|
||||
end
|
||||
|
||||
it "respects the subset param" do
|
||||
get "/tag/#{tag.name}/l/new.json", params: { subset: "topics" }
|
||||
|
||||
ids = extract_topic_ids(response)
|
||||
expect(ids).to contain_exactly(new_topic_with_tag.id)
|
||||
|
||||
get "/tag/#{tag.name}/l/new.json", params: { subset: "replies" }
|
||||
|
||||
ids = extract_topic_ids(response)
|
||||
expect(ids).to contain_exactly(new_reply_with_tag.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
462
spec/system/new_topic_list_spec.rb
Normal file
462
spec/system/new_topic_list_spec.rb
Normal file
|
@ -0,0 +1,462 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
describe "New topic list", type: :system do
|
||||
fab!(:user) { Fabricate(:user) }
|
||||
fab!(:group) { Fabricate(:group, users: [user]) }
|
||||
fab!(:category) { Fabricate(:category) }
|
||||
fab!(:tag) { Fabricate(:tag) }
|
||||
|
||||
fab!(:new_reply) do
|
||||
Fabricate(:post).topic.tap do |topic|
|
||||
TopicUser.change(
|
||||
user.id,
|
||||
topic.id,
|
||||
notification_level: TopicUser.notification_levels[:tracking],
|
||||
)
|
||||
TopicUser.update_last_read(user, topic.id, 1, 1, 1)
|
||||
Fabricate(:post, topic: topic)
|
||||
end
|
||||
end
|
||||
|
||||
fab!(:new_topic) { Fabricate(:post).topic }
|
||||
|
||||
fab!(:old_topic) do
|
||||
Fabricate(:post).topic.tap { |topic| TopicUser.update_last_read(user, topic.id, 1, 1, 1) }
|
||||
end
|
||||
|
||||
fab!(:new_reply_in_category) do
|
||||
Fabricate(:post, topic: Fabricate(:topic, category: category)).topic.tap do |topic|
|
||||
TopicUser.change(
|
||||
user.id,
|
||||
topic.id,
|
||||
notification_level: TopicUser.notification_levels[:tracking],
|
||||
)
|
||||
TopicUser.update_last_read(user, topic.id, 1, 1, 1)
|
||||
Fabricate(:post, topic: topic)
|
||||
end
|
||||
end
|
||||
|
||||
fab!(:new_topic_in_category) do
|
||||
Fabricate(:post, topic: Fabricate(:topic, category: category)).topic
|
||||
end
|
||||
|
||||
fab!(:old_topic_in_category) do
|
||||
Fabricate(:post, topic: Fabricate(:topic, category: category)).topic.tap do |topic|
|
||||
TopicUser.update_last_read(user, topic.id, 1, 1, 1)
|
||||
end
|
||||
end
|
||||
|
||||
fab!(:new_reply_with_tag) do
|
||||
Fabricate(:post, topic: Fabricate(:topic, tags: [tag])).topic.tap do |topic|
|
||||
TopicUser.change(
|
||||
user.id,
|
||||
topic.id,
|
||||
notification_level: TopicUser.notification_levels[:tracking],
|
||||
)
|
||||
TopicUser.update_last_read(user, topic.id, 1, 1, 1)
|
||||
Fabricate(:post, topic: topic)
|
||||
end
|
||||
end
|
||||
|
||||
fab!(:new_topic_with_tag) { Fabricate(:post, topic: Fabricate(:topic, tags: [tag])).topic }
|
||||
|
||||
fab!(:old_topic_with_tag) do
|
||||
Fabricate(:post, topic: Fabricate(:topic, tags: [tag])).topic.tap do |topic|
|
||||
TopicUser.update_last_read(user, topic.id, 1, 1, 1)
|
||||
end
|
||||
end
|
||||
|
||||
let(:topic_list) { PageObjects::Components::TopicList.new }
|
||||
let(:tabs_toggle) { PageObjects::Components::NewTopicListToggle.new }
|
||||
|
||||
before { sign_in(user) }
|
||||
|
||||
shared_examples "new list new topics and replies toggle" do
|
||||
context "when the new new view is enabled" do
|
||||
before { SiteSetting.experimental_new_new_view_groups = group.name }
|
||||
|
||||
it "shows all new topics and replies by default" do
|
||||
visit("/new")
|
||||
|
||||
expect(topic_list).to have_topics(count: 6)
|
||||
[
|
||||
new_reply,
|
||||
new_topic,
|
||||
new_reply_in_category,
|
||||
new_topic_in_category,
|
||||
new_reply_with_tag,
|
||||
new_topic_with_tag,
|
||||
].each { |topic| expect(topic_list).to have_topic(topic) }
|
||||
|
||||
expect(tabs_toggle.all_tab).to have_count(6)
|
||||
expect(tabs_toggle.replies_tab).to have_count(3)
|
||||
expect(tabs_toggle.topics_tab).to have_count(3)
|
||||
|
||||
expect(tabs_toggle.all_tab).to be_active
|
||||
expect(tabs_toggle.replies_tab).to be_inactive
|
||||
expect(tabs_toggle.topics_tab).to be_inactive
|
||||
end
|
||||
|
||||
it "respects the subset query param and activates the appropriate tab" do
|
||||
visit("/new?subset=topics")
|
||||
|
||||
expect(tabs_toggle.all_tab).to be_inactive
|
||||
expect(tabs_toggle.replies_tab).to be_inactive
|
||||
expect(tabs_toggle.topics_tab).to be_active
|
||||
|
||||
visit("/new?subset=replies")
|
||||
|
||||
expect(tabs_toggle.all_tab).to be_inactive
|
||||
expect(tabs_toggle.replies_tab).to be_active
|
||||
expect(tabs_toggle.topics_tab).to be_inactive
|
||||
end
|
||||
|
||||
it "shows only new topics when the user switches to the Topics tab" do
|
||||
visit("/new")
|
||||
tabs_toggle.topics_tab.click
|
||||
|
||||
expect(topic_list).to have_topics(count: 3)
|
||||
[new_topic, new_topic_in_category, new_topic_with_tag].each do |topic|
|
||||
expect(topic_list).to have_topic(topic)
|
||||
end
|
||||
|
||||
expect(tabs_toggle.all_tab).to be_inactive
|
||||
expect(tabs_toggle.replies_tab).to be_inactive
|
||||
expect(tabs_toggle.topics_tab).to be_active
|
||||
|
||||
expect(tabs_toggle.all_tab).to have_count(6)
|
||||
expect(tabs_toggle.replies_tab).to have_count(3)
|
||||
expect(tabs_toggle.topics_tab).to have_count(3)
|
||||
|
||||
expect(page).to have_current_path("/new?subset=topics")
|
||||
end
|
||||
|
||||
it "shows only topics with new replies when the user switches to the Replies tab" do
|
||||
visit("/new")
|
||||
tabs_toggle.replies_tab.click
|
||||
|
||||
expect(topic_list).to have_topics(count: 3)
|
||||
[new_reply, new_reply_in_category, new_reply_with_tag].each do |topic|
|
||||
expect(topic_list).to have_topic(topic)
|
||||
end
|
||||
|
||||
expect(tabs_toggle.all_tab).to be_inactive
|
||||
expect(tabs_toggle.replies_tab).to be_active
|
||||
expect(tabs_toggle.topics_tab).to be_inactive
|
||||
|
||||
expect(tabs_toggle.all_tab).to have_count(6)
|
||||
expect(tabs_toggle.replies_tab).to have_count(3)
|
||||
expect(tabs_toggle.topics_tab).to have_count(3)
|
||||
|
||||
expect(page).to have_current_path("/new?subset=replies")
|
||||
end
|
||||
|
||||
it "strips out the subset query params when switching back to the All tab from any of the other tabs" do
|
||||
visit("/new")
|
||||
tabs_toggle.replies_tab.click
|
||||
|
||||
expect(tabs_toggle.all_tab).to be_inactive
|
||||
expect(tabs_toggle.replies_tab).to be_active
|
||||
|
||||
expect(page).to have_current_path("/new?subset=replies")
|
||||
|
||||
tabs_toggle.all_tab.click
|
||||
|
||||
expect(tabs_toggle.all_tab).to be_active
|
||||
expect(tabs_toggle.replies_tab).to be_inactive
|
||||
expect(page).to have_current_path("/new")
|
||||
end
|
||||
|
||||
it "live-updates the counts shown on the tabs" do
|
||||
visit("/new")
|
||||
|
||||
expect(tabs_toggle.all_tab).to have_count(6)
|
||||
expect(tabs_toggle.replies_tab).to have_count(3)
|
||||
expect(tabs_toggle.topics_tab).to have_count(3)
|
||||
|
||||
TopicUser.update_last_read(user, new_reply_in_category.id, 2, 1, 1)
|
||||
|
||||
expect(tabs_toggle.all_tab).to have_count(5)
|
||||
expect(tabs_toggle.replies_tab).to have_count(2)
|
||||
expect(tabs_toggle.topics_tab).to have_count(3)
|
||||
|
||||
TopicUser.update_last_read(user, new_topic.id, 1, 1, 1)
|
||||
|
||||
expect(tabs_toggle.all_tab).to have_count(4)
|
||||
expect(tabs_toggle.replies_tab).to have_count(2)
|
||||
expect(tabs_toggle.topics_tab).to have_count(2)
|
||||
end
|
||||
|
||||
context "when the /new topic list is scoped to a category" do
|
||||
it "shows new topics and replies in the category" do
|
||||
visit("/c/#{category.slug}/#{category.id}/l/new")
|
||||
expect(topic_list).to have_topics(count: 2)
|
||||
expect(topic_list).to have_topic(new_reply_in_category)
|
||||
expect(topic_list).to have_topic(new_topic_in_category)
|
||||
|
||||
expect(tabs_toggle.all_tab).to be_active
|
||||
expect(tabs_toggle.replies_tab).to be_inactive
|
||||
expect(tabs_toggle.topics_tab).to be_inactive
|
||||
|
||||
expect(tabs_toggle.all_tab).to have_count(2)
|
||||
expect(tabs_toggle.replies_tab).to have_count(1)
|
||||
expect(tabs_toggle.topics_tab).to have_count(1)
|
||||
end
|
||||
|
||||
it "shows only new topics in the category when the user switches to the Topics tab" do
|
||||
visit("/c/#{category.slug}/#{category.id}/l/new")
|
||||
tabs_toggle.topics_tab.click
|
||||
|
||||
expect(topic_list).to have_topics(count: 1)
|
||||
expect(topic_list).to have_topic(new_topic_in_category)
|
||||
|
||||
expect(tabs_toggle.all_tab).to be_inactive
|
||||
expect(tabs_toggle.replies_tab).to be_inactive
|
||||
expect(tabs_toggle.topics_tab).to be_active
|
||||
|
||||
expect(tabs_toggle.all_tab).to have_count(2)
|
||||
expect(tabs_toggle.replies_tab).to have_count(1)
|
||||
expect(tabs_toggle.topics_tab).to have_count(1)
|
||||
|
||||
expect(page).to have_current_path(
|
||||
"/c/#{category.slug}/#{category.id}/l/new?subset=topics",
|
||||
)
|
||||
end
|
||||
|
||||
it "shows only topics with new replies in the category when the user switches to the Replies tab" do
|
||||
visit("/c/#{category.slug}/#{category.id}/l/new")
|
||||
tabs_toggle.replies_tab.click
|
||||
|
||||
expect(topic_list).to have_topics(count: 1)
|
||||
expect(topic_list).to have_topic(new_reply_in_category)
|
||||
|
||||
expect(tabs_toggle.all_tab).to be_inactive
|
||||
expect(tabs_toggle.replies_tab).to be_active
|
||||
expect(tabs_toggle.topics_tab).to be_inactive
|
||||
|
||||
expect(tabs_toggle.all_tab).to have_count(2)
|
||||
expect(tabs_toggle.replies_tab).to have_count(1)
|
||||
expect(tabs_toggle.topics_tab).to have_count(1)
|
||||
|
||||
expect(page).to have_current_path(
|
||||
"/c/#{category.slug}/#{category.id}/l/new?subset=replies",
|
||||
)
|
||||
end
|
||||
|
||||
it "respects the subset query param and activates the appropriate tab" do
|
||||
visit("/c/#{category.slug}/#{category.id}/l/new?subset=topics")
|
||||
|
||||
expect(tabs_toggle.all_tab).to be_inactive
|
||||
expect(tabs_toggle.replies_tab).to be_inactive
|
||||
expect(tabs_toggle.topics_tab).to be_active
|
||||
|
||||
visit("/c/#{category.slug}/#{category.id}/l/new?subset=replies")
|
||||
|
||||
expect(tabs_toggle.all_tab).to be_inactive
|
||||
expect(tabs_toggle.replies_tab).to be_active
|
||||
expect(tabs_toggle.topics_tab).to be_inactive
|
||||
end
|
||||
|
||||
it "live-updates the counts shown on the tabs" do
|
||||
Fabricate(:post, topic: Fabricate(:topic, category: category))
|
||||
|
||||
visit("/c/#{category.slug}/#{category.id}/l/new")
|
||||
|
||||
expect(tabs_toggle.all_tab).to have_count(3)
|
||||
expect(tabs_toggle.replies_tab).to have_count(1)
|
||||
expect(tabs_toggle.topics_tab).to have_count(2)
|
||||
|
||||
TopicUser.update_last_read(user, new_topic_in_category.id, 1, 1, 1)
|
||||
|
||||
expect(tabs_toggle.all_tab).to have_count(2)
|
||||
expect(tabs_toggle.replies_tab).to have_count(1)
|
||||
expect(tabs_toggle.topics_tab).to have_count(1)
|
||||
end
|
||||
end
|
||||
|
||||
context "when the /new topic list is scoped to a tag" do
|
||||
it "shows new topics and replies with the tag" do
|
||||
visit("/tag/#{tag.name}/l/new")
|
||||
expect(topic_list).to have_topics(count: 2)
|
||||
[new_reply_with_tag, new_topic_with_tag].each do |topic|
|
||||
expect(topic_list).to have_topic(topic)
|
||||
end
|
||||
|
||||
expect(tabs_toggle.all_tab).to be_active
|
||||
expect(tabs_toggle.replies_tab).to be_inactive
|
||||
expect(tabs_toggle.topics_tab).to be_inactive
|
||||
|
||||
expect(tabs_toggle.all_tab).to have_count(2)
|
||||
expect(tabs_toggle.replies_tab).to have_count(1)
|
||||
expect(tabs_toggle.topics_tab).to have_count(1)
|
||||
end
|
||||
|
||||
it "shows only new topics with the tag when the user switches to the Topics tab" do
|
||||
visit("/tag/#{tag.name}/l/new")
|
||||
tabs_toggle.topics_tab.click
|
||||
|
||||
expect(topic_list).to have_topics(count: 1)
|
||||
expect(topic_list).to have_topic(new_topic_with_tag)
|
||||
|
||||
expect(tabs_toggle.all_tab).to be_inactive
|
||||
expect(tabs_toggle.replies_tab).to be_inactive
|
||||
expect(tabs_toggle.topics_tab).to be_active
|
||||
|
||||
expect(tabs_toggle.all_tab).to have_count(2)
|
||||
expect(tabs_toggle.replies_tab).to have_count(1)
|
||||
expect(tabs_toggle.topics_tab).to have_count(1)
|
||||
|
||||
expect(page).to have_current_path("/tag/#{tag.name}/l/new?subset=topics")
|
||||
end
|
||||
|
||||
it "shows only topics with new replies with the tag when the user switches to the Replies tab" do
|
||||
visit("/tag/#{tag.name}/l/new")
|
||||
|
||||
tabs_toggle.replies_tab.click
|
||||
|
||||
expect(topic_list).to have_topics(count: 1)
|
||||
expect(topic_list).to have_topic(new_reply_with_tag)
|
||||
|
||||
expect(tabs_toggle.all_tab).to be_inactive
|
||||
expect(tabs_toggle.replies_tab).to be_active
|
||||
expect(tabs_toggle.topics_tab).to be_inactive
|
||||
|
||||
expect(tabs_toggle.all_tab).to have_count(2)
|
||||
expect(tabs_toggle.replies_tab).to have_count(1)
|
||||
expect(tabs_toggle.topics_tab).to have_count(1)
|
||||
|
||||
expect(page).to have_current_path("/tag/#{tag.name}/l/new?subset=replies")
|
||||
end
|
||||
|
||||
it "respects the subset query param and activates the appropriate tab" do
|
||||
visit("/tag/#{tag.name}/l/new?subset=topics")
|
||||
|
||||
expect(tabs_toggle.all_tab).to be_inactive
|
||||
expect(tabs_toggle.replies_tab).to be_inactive
|
||||
expect(tabs_toggle.topics_tab).to be_active
|
||||
|
||||
visit("/tag/#{tag.name}/l/new?subset=replies")
|
||||
|
||||
expect(tabs_toggle.all_tab).to be_inactive
|
||||
expect(tabs_toggle.replies_tab).to be_active
|
||||
expect(tabs_toggle.topics_tab).to be_inactive
|
||||
end
|
||||
|
||||
it "live-updates the counts shown on the tabs" do
|
||||
Fabricate(:post, topic: Fabricate(:topic, tags: [tag]))
|
||||
|
||||
visit("/tag/#{tag.name}/l/new")
|
||||
|
||||
expect(tabs_toggle.all_tab).to have_count(3)
|
||||
expect(tabs_toggle.replies_tab).to have_count(1)
|
||||
expect(tabs_toggle.topics_tab).to have_count(2)
|
||||
|
||||
TopicUser.update_last_read(user, new_topic_with_tag.id, 1, 1, 1)
|
||||
|
||||
expect(tabs_toggle.all_tab).to have_count(2)
|
||||
expect(tabs_toggle.replies_tab).to have_count(1)
|
||||
expect(tabs_toggle.topics_tab).to have_count(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when the new new view is not enabled" do
|
||||
before { SiteSetting.experimental_new_new_view_groups = "" }
|
||||
|
||||
it "doesn't show the tabs toggle" do
|
||||
visit("/new")
|
||||
expect(tabs_toggle).to be_not_rendered
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when on mobile", mobile: true do
|
||||
include_examples "new list new topics and replies toggle"
|
||||
|
||||
context "when there are no new topics" do
|
||||
before do
|
||||
SiteSetting.experimental_new_new_view_groups = group.name
|
||||
|
||||
[new_topic, new_topic_in_category, new_topic_with_tag].each do |topic|
|
||||
TopicUser.update_last_read(user, topic.id, 1, 1, 1)
|
||||
end
|
||||
end
|
||||
|
||||
it "keeps the Topics tab even when there are no new topics" do
|
||||
visit("/new")
|
||||
|
||||
expect(tabs_toggle.all_tab).to be_visible
|
||||
expect(tabs_toggle.replies_tab).to be_visible
|
||||
expect(tabs_toggle.topics_tab).to be_visible
|
||||
|
||||
expect(tabs_toggle.all_tab).to have_count(3)
|
||||
expect(tabs_toggle.replies_tab).to have_count(3)
|
||||
expect(tabs_toggle.topics_tab).to have_count(0)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there are no new replies" do
|
||||
before do
|
||||
SiteSetting.experimental_new_new_view_groups = group.name
|
||||
|
||||
[new_reply, new_reply_in_category, new_reply_with_tag].each do |topic|
|
||||
TopicUser.update_last_read(user, topic.id, 2, 1, 1)
|
||||
end
|
||||
end
|
||||
|
||||
it "keeps the Replies tab even when there are no new replies" do
|
||||
visit("/new")
|
||||
|
||||
expect(tabs_toggle.all_tab).to be_visible
|
||||
expect(tabs_toggle.replies_tab).to be_visible
|
||||
expect(tabs_toggle.topics_tab).to be_visible
|
||||
|
||||
expect(tabs_toggle.all_tab).to have_count(3)
|
||||
expect(tabs_toggle.replies_tab).to have_count(0)
|
||||
expect(tabs_toggle.topics_tab).to have_count(3)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when on desktop" do
|
||||
include_examples "new list new topics and replies toggle"
|
||||
|
||||
context "when there's only new topics" do
|
||||
before do
|
||||
SiteSetting.experimental_new_new_view_groups = group.name
|
||||
|
||||
[new_reply, new_reply_in_category, new_reply_with_tag].each do |topic|
|
||||
TopicUser.update_last_read(user, topic.id, 2, 1, 1)
|
||||
end
|
||||
end
|
||||
|
||||
it "doesn't render the toggle and only shows a static label for new topics" 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),
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there's only new replies" do
|
||||
before do
|
||||
SiteSetting.experimental_new_new_view_groups = group.name
|
||||
|
||||
[new_topic, new_topic_in_category, new_topic_with_tag].each do |topic|
|
||||
TopicUser.update_last_read(user, topic.id, 1, 1, 1)
|
||||
end
|
||||
end
|
||||
|
||||
it "doesn't render the toggle and only shows a static label for new replies" 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),
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
31
spec/system/page_objects/components/new_topic_list_toggle.rb
Normal file
31
spec/system/page_objects/components/new_topic_list_toggle.rb
Normal file
|
@ -0,0 +1,31 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module PageObjects
|
||||
module Components
|
||||
class NewTopicListToggle < PageObjects::Components::Base
|
||||
COMMON_SELECTOR = ".topics-replies-toggle"
|
||||
|
||||
ALL_SELECTOR = "#{COMMON_SELECTOR}.all"
|
||||
REPLIES_SELECTOR = "#{COMMON_SELECTOR}.replies"
|
||||
TOPICS_SELECTOR = "#{COMMON_SELECTOR}.topics"
|
||||
|
||||
def not_rendered?
|
||||
has_no_css?(COMMON_SELECTOR)
|
||||
end
|
||||
|
||||
def all_tab
|
||||
@all_tab ||= PageObjects::Components::NewTopicListToggleTab.new("all", ALL_SELECTOR)
|
||||
end
|
||||
|
||||
def replies_tab
|
||||
@replies_tab ||=
|
||||
PageObjects::Components::NewTopicListToggleTab.new("replies", REPLIES_SELECTOR)
|
||||
end
|
||||
|
||||
def topics_tab
|
||||
@topics_tab ||=
|
||||
PageObjects::Components::NewTopicListToggleTab.new("topics", TOPICS_SELECTOR)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,42 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module PageObjects
|
||||
module Components
|
||||
class NewTopicListToggleTab < PageObjects::Components::Base
|
||||
def initialize(name, selector)
|
||||
super()
|
||||
@name = name
|
||||
@selector = selector
|
||||
end
|
||||
|
||||
def active?
|
||||
has_css?("#{@selector}.active")
|
||||
end
|
||||
|
||||
def inactive?
|
||||
has_no_css?("#{@selector}.active") && has_css?(@selector)
|
||||
end
|
||||
|
||||
def visible?
|
||||
has_css?(@selector)
|
||||
end
|
||||
|
||||
def has_count?(count)
|
||||
expected_label =
|
||||
(
|
||||
if count > 0
|
||||
I18n.t("js.filters.new.#{@name}_with_count", count: count)
|
||||
else
|
||||
I18n.t("js.filters.new.#{@name}")
|
||||
end
|
||||
)
|
||||
|
||||
has_selector?(@selector, text: expected_label)
|
||||
end
|
||||
|
||||
def click
|
||||
find(@selector).click
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue
Block a user