mirror of
https://github.com/discourse/discourse.git
synced 2025-01-30 05:34:03 +08:00
FEATURE: new dismiss button for combined new and unread view (#21817)
Display modal for combined new and unread view with options: - [x] Dismiss new topics - [x] Dismiss new posts - [ ] Stop tracking these topics so they stop appearing in my new list
This commit is contained in:
parent
899969fd5d
commit
af74cf5c77
|
@ -1,5 +1,6 @@
|
|||
import { alias, empty, equal, gt, not, 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";
|
||||
import I18n from "I18n";
|
||||
import Topic from "discourse/models/topic";
|
||||
|
@ -56,6 +57,32 @@ const controllerOpts = {
|
|||
return this._isFilterPage(filter, "new") && topicsLength > 0;
|
||||
},
|
||||
|
||||
callResetNew(dismissPosts = false, dismissTopics = false, untrack = false) {
|
||||
const tracked =
|
||||
(this.router.currentRoute.queryParams["f"] ||
|
||||
this.router.currentRoute.queryParams["filter"]) === "tracked";
|
||||
|
||||
let topicIds = this.selected
|
||||
? this.selected.map((topic) => topic.id)
|
||||
: null;
|
||||
|
||||
Topic.resetNew(this.category, !this.noSubcategories, {
|
||||
tracked,
|
||||
topicIds,
|
||||
dismissPosts,
|
||||
dismissTopics,
|
||||
untrack,
|
||||
}).then((result) => {
|
||||
if (result.topic_ids) {
|
||||
this.topicTrackingState.removeTopics(result.topic_ids);
|
||||
}
|
||||
this.send(
|
||||
"refresh",
|
||||
tracked ? { skipResettingParams: ["filter", "f"] } : {}
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
// Show newly inserted topics
|
||||
@action
|
||||
showInserted(event) {
|
||||
|
@ -114,26 +141,6 @@ const controllerOpts = {
|
|||
}
|
||||
});
|
||||
},
|
||||
|
||||
resetNew() {
|
||||
const tracked =
|
||||
(this.router.currentRoute.queryParams["f"] ||
|
||||
this.router.currentRoute.queryParams["filter"]) === "tracked";
|
||||
|
||||
let topicIds = this.selected
|
||||
? this.selected.map((topic) => topic.id)
|
||||
: null;
|
||||
|
||||
Topic.resetNew(this.category, !this.noSubcategories, {
|
||||
tracked,
|
||||
topicIds,
|
||||
}).then(() =>
|
||||
this.send(
|
||||
"refresh",
|
||||
tracked ? { skipResettingParams: ["filter", "f"] } : {}
|
||||
)
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
afterRefresh(filter, list, listModel = list) {
|
||||
|
@ -213,4 +220,8 @@ const controllerOpts = {
|
|||
},
|
||||
};
|
||||
|
||||
export default DiscoveryController.extend(controllerOpts, BulkTopicSelection);
|
||||
export default DiscoveryController.extend(
|
||||
controllerOpts,
|
||||
BulkTopicSelection,
|
||||
DismissTopics
|
||||
);
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
import Controller from "@ember/controller";
|
||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default class DismissNewController extends Controller.extend(
|
||||
ModalFunctionality
|
||||
) {
|
||||
@action
|
||||
dismiss() {
|
||||
this.dismissCallback();
|
||||
this.send("closeModal");
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ import DiscoverySortableController from "discourse/controllers/discovery-sortabl
|
|||
import { inject as controller } from "@ember/controller";
|
||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
||||
import BulkTopicSelection from "discourse/mixins/bulk-topic-selection";
|
||||
import DismissTopics from "discourse/mixins/dismiss-topics";
|
||||
import FilterModeMixin from "discourse/mixins/filter-mode";
|
||||
import I18n from "I18n";
|
||||
import NavItem from "discourse/models/nav-item";
|
||||
|
@ -13,6 +14,7 @@ import { inject as service } from "@ember/service";
|
|||
|
||||
export default DiscoverySortableController.extend(
|
||||
BulkTopicSelection,
|
||||
DismissTopics,
|
||||
FilterModeMixin,
|
||||
{
|
||||
application: controller(),
|
||||
|
@ -91,8 +93,7 @@ export default DiscoverySortableController.extend(
|
|||
return this._isFilterPage(filter, "new") && topicsLength > 0;
|
||||
},
|
||||
|
||||
@action
|
||||
resetNew() {
|
||||
callResetNew(dismissPosts = false, dismissTopics = false, untrack = false) {
|
||||
const tracked =
|
||||
(this.router.currentRoute.queryParams["f"] ||
|
||||
this.router.currentRoute.queryParams["filter"]) === "tracked";
|
||||
|
@ -103,9 +104,15 @@ export default DiscoverySortableController.extend(
|
|||
tracked,
|
||||
tag: this.tag,
|
||||
topicIds,
|
||||
}).then(() =>
|
||||
this.refresh(tracked ? { skipResettingParams: ["filter", "f"] } : {})
|
||||
);
|
||||
dismissPosts,
|
||||
dismissTopics,
|
||||
untrack,
|
||||
}).then((result) => {
|
||||
if (result.topic_ids) {
|
||||
this.topicTrackingState.removeTopics(result.topic_ids);
|
||||
}
|
||||
this.refresh(tracked ? { skipResettingParams: ["filter", "f"] } : {});
|
||||
});
|
||||
},
|
||||
|
||||
@action
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import Mixin from "@ember/object/mixin";
|
||||
import User from "discourse/models/user";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Mixin.create({
|
||||
actions: {
|
||||
resetNew() {
|
||||
const user = User.current();
|
||||
if (!user.new_new_view_enabled) {
|
||||
return this.callResetNew();
|
||||
}
|
||||
const controller = showModal("dismiss-new", {
|
||||
model: {
|
||||
dismissTopics: true,
|
||||
dismissPosts: true,
|
||||
},
|
||||
titleTranslated: I18n.t("topics.bulk.dismiss_new_modal.title"),
|
||||
});
|
||||
|
||||
controller.set("dismissCallback", () => {
|
||||
this.callResetNew(
|
||||
controller.model.dismissPosts,
|
||||
controller.model.dismissTopics,
|
||||
controller.model.untrack
|
||||
);
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
|
@ -851,6 +851,18 @@ Topic.reopenClass({
|
|||
data.topic_ids = topicIds;
|
||||
}
|
||||
|
||||
if (opts.dismissPosts) {
|
||||
data.dismiss_posts = opts.dismissPosts;
|
||||
}
|
||||
|
||||
if (opts.dismissTopics) {
|
||||
data.dismiss_topics = opts.dismissTopics;
|
||||
}
|
||||
|
||||
if (opts.untrack) {
|
||||
data.untrack = opts.untrack;
|
||||
}
|
||||
|
||||
return ajax("/topics/reset-new", { type: "PUT", data });
|
||||
},
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<DModalBody>
|
||||
<p>
|
||||
<PreferenceCheckbox
|
||||
@labelKey="topics.bulk.dismiss_new_modal.topics"
|
||||
@checked={{this.model.dismissTopics}}
|
||||
@class="dismiss-topics"
|
||||
/>
|
||||
<PreferenceCheckbox
|
||||
@labelKey="topics.bulk.dismiss_new_modal.posts"
|
||||
@checked={{this.model.dismissPosts}}
|
||||
@class="dismiss-posts"
|
||||
/>
|
||||
<PreferenceCheckbox
|
||||
@labelKey="topics.bulk.dismiss_new_modal.untrack"
|
||||
@checked={{this.model.untrack}}
|
||||
@class="untrack"
|
||||
/>
|
||||
</p>
|
||||
</DModalBody>
|
||||
|
||||
<div class="modal-footer">
|
||||
<DButton
|
||||
@class="btn-primary"
|
||||
@action="dismiss"
|
||||
@icon="check"
|
||||
@id="dismiss-read-confirm"
|
||||
@label="topics.bulk.dismiss"
|
||||
/>
|
||||
</div>
|
|
@ -1059,7 +1059,20 @@ class TopicsController < ApplicationController
|
|||
elsif params[:tag_id].present?
|
||||
Topic.joins(:tags).where(tags: { name: params[:tag_id] })
|
||||
else
|
||||
new_results = TopicQuery.new(current_user).new_results(limit: false)
|
||||
new_results =
|
||||
if current_user.new_new_view_enabled?
|
||||
if (params[:dismiss_topics] && params[:dismiss_posts])
|
||||
TopicQuery.new(current_user).new_and_unread_results(limit: false)
|
||||
elsif params[:dismiss_topics]
|
||||
TopicQuery.new(current_user).new_results(limit: false)
|
||||
elsif params[:dismiss_posts]
|
||||
TopicQuery.new(current_user).unread_results(limit: false)
|
||||
else
|
||||
Topic.none
|
||||
end
|
||||
else
|
||||
TopicQuery.new(current_user).new_results(limit: false)
|
||||
end
|
||||
if params[:tracked].to_s == "true"
|
||||
TopicQuery.tracked_filter(new_results, current_user.id)
|
||||
else
|
||||
|
@ -1077,11 +1090,30 @@ class TopicsController < ApplicationController
|
|||
topic_scope = topic_scope.where(id: topic_ids)
|
||||
end
|
||||
|
||||
dismissed_topic_ids =
|
||||
TopicsBulkAction.new(current_user, topic_scope.pluck(:id), type: "dismiss_topics").perform!
|
||||
TopicTrackingState.publish_dismiss_new(current_user.id, topic_ids: dismissed_topic_ids)
|
||||
dismissed_topic_ids = []
|
||||
dismissed_post_topic_ids = []
|
||||
if !current_user.new_new_view_enabled? || params[:dismiss_topics]
|
||||
dismissed_topic_ids =
|
||||
TopicsBulkAction.new(current_user, topic_scope.pluck(:id), type: "dismiss_topics").perform!
|
||||
TopicTrackingState.publish_dismiss_new(current_user.id, topic_ids: dismissed_topic_ids)
|
||||
end
|
||||
|
||||
render body: nil
|
||||
if params[:dismiss_posts]
|
||||
if params[:untrack]
|
||||
dismissed_post_topic_ids =
|
||||
TopicsBulkAction.new(
|
||||
current_user,
|
||||
topic_scope.pluck(:id),
|
||||
type: "change_notification_level",
|
||||
notification_level_id: NotificationLevels.topic_levels[:regular],
|
||||
).perform!
|
||||
else
|
||||
dismissed_post_topic_ids =
|
||||
TopicsBulkAction.new(current_user, topic_scope.pluck(:id), type: "dismiss_posts").perform!
|
||||
end
|
||||
end
|
||||
|
||||
render_json_dump topic_ids: dismissed_topic_ids.concat(dismissed_post_topic_ids).uniq
|
||||
end
|
||||
|
||||
def convert_topic
|
||||
|
|
|
@ -2866,6 +2866,11 @@ en:
|
|||
dismiss_tooltip: "Dismiss just new posts or stop tracking topics"
|
||||
also_dismiss_topics: "Stop tracking these topics so they never show up as unread for me again"
|
||||
dismiss_new: "Dismiss New"
|
||||
dismiss_new_modal:
|
||||
title: "Dismiss new"
|
||||
topics: "Dismiss new topics"
|
||||
posts: "Dismiss new posts"
|
||||
untrack: "Stop tracking these topics so they stop appearing in my new list"
|
||||
dismiss_new_with_selected:
|
||||
one: "Dismiss New (%{count})"
|
||||
other: "Dismiss New (%{count})"
|
||||
|
|
|
@ -4061,6 +4061,168 @@ RSpec.describe TopicsController do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "new and unread" do
|
||||
fab!(:group) { Fabricate(:group) }
|
||||
fab!(:new_topic) { Fabricate(:topic) }
|
||||
fab!(:unread_topic) { Fabricate(:topic, highest_post_number: 3) }
|
||||
fab!(:topic_user) do
|
||||
Fabricate(
|
||||
:topic_user,
|
||||
topic: unread_topic,
|
||||
user: user,
|
||||
notification_level: NotificationLevels.topic_levels[:tracking],
|
||||
last_read_post_number: 1,
|
||||
)
|
||||
end
|
||||
|
||||
before do
|
||||
create_post(topic: unread_topic)
|
||||
create_post(topic: unread_topic)
|
||||
user.groups << group
|
||||
SiteSetting.experimental_new_new_view_groups = group.id
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
it "dismisses new topics" do
|
||||
put "/topics/reset-new.json"
|
||||
topics = TopicQuery.new(user).new_and_unread_results(limit: false)
|
||||
expect(topics).to eq([unread_topic, new_topic])
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.parsed_body["topic_ids"]).to eq([])
|
||||
|
||||
put "/topics/reset-new.json", params: { dismiss_topics: true }
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.parsed_body["topic_ids"]).to eq([new_topic.id])
|
||||
|
||||
topics = TopicQuery.new(user).new_and_unread_results(limit: false)
|
||||
expect(topics).to eq([unread_topic])
|
||||
expect(DismissedTopicUser.where(user: user).count).to eq(1)
|
||||
expect(DismissedTopicUser.where(user: user).first.topic_id).to eq(new_topic.id)
|
||||
expect(topic_user.reload.notification_level).to eq(
|
||||
NotificationLevels.topic_levels[:tracking],
|
||||
)
|
||||
end
|
||||
|
||||
it "dismisses unread topics" do
|
||||
put "/topics/reset-new.json"
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.parsed_body["topic_ids"]).to eq([])
|
||||
topics = TopicQuery.new(user).new_and_unread_results(limit: false)
|
||||
expect(topics).to eq([unread_topic, new_topic])
|
||||
|
||||
put "/topics/reset-new.json", params: { dismiss_posts: true }
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.parsed_body["topic_ids"]).to eq([unread_topic.id])
|
||||
|
||||
topics = TopicQuery.new(user).new_and_unread_results(limit: false)
|
||||
expect(topics).to eq([new_topic])
|
||||
expect(DismissedTopicUser.count).to eq(0)
|
||||
expect(topic_user.reload.notification_level).to eq(
|
||||
NotificationLevels.topic_levels[:tracking],
|
||||
)
|
||||
end
|
||||
|
||||
it "untrack topics" do
|
||||
expect(topic_user.notification_level).to eq(NotificationLevels.topic_levels[:tracking])
|
||||
put "/topics/reset-new.json", params: { dismiss_posts: true, untrack: true }
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.parsed_body["topic_ids"]).to eq([unread_topic.id])
|
||||
|
||||
expect(topic_user.reload.notification_level).to eq(
|
||||
NotificationLevels.topic_levels[:regular],
|
||||
)
|
||||
end
|
||||
|
||||
it "dismisses new topics, unread posts and untrack" do
|
||||
put "/topics/reset-new.json",
|
||||
params: {
|
||||
dismiss_topics: true,
|
||||
dismiss_posts: true,
|
||||
untrack: true,
|
||||
}
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.parsed_body["topic_ids"]).to eq([new_topic.id, unread_topic.id])
|
||||
|
||||
topics = TopicQuery.new(user).new_and_unread_results(limit: false)
|
||||
expect(topics).to be_empty
|
||||
expect(DismissedTopicUser.where(user: user).count).to eq(1)
|
||||
expect(DismissedTopicUser.where(user: user).first.topic_id).to eq(new_topic.id)
|
||||
|
||||
expect(user.topic_users.map(&:notification_level).uniq).to eq(
|
||||
[NotificationLevels.topic_levels[:regular]],
|
||||
)
|
||||
end
|
||||
|
||||
context "when category" do
|
||||
fab!(:category) { Fabricate(:category) }
|
||||
fab!(:new_topic_2) { Fabricate(:topic, category: category) }
|
||||
fab!(:unread_topic_2) { Fabricate(:topic, category: category, highest_post_number: 3) }
|
||||
fab!(:topic_user) do
|
||||
Fabricate(
|
||||
:topic_user,
|
||||
topic: unread_topic_2,
|
||||
user: user,
|
||||
notification_level: NotificationLevels.topic_levels[:tracking],
|
||||
last_read_post_number: 1,
|
||||
)
|
||||
end
|
||||
|
||||
it "dismisses new topics, unread posts and untrack for specific category" do
|
||||
topics = TopicQuery.new(user).new_and_unread_results(limit: false)
|
||||
expect(topics).to match_array([new_topic, new_topic_2, unread_topic, unread_topic_2])
|
||||
|
||||
put "/topics/reset-new.json",
|
||||
params: {
|
||||
dismiss_topics: true,
|
||||
dismiss_posts: true,
|
||||
untrack: true,
|
||||
category_id: category.id,
|
||||
}
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.parsed_body["topic_ids"]).to eq([new_topic_2.id, unread_topic_2.id])
|
||||
|
||||
topics = TopicQuery.new(user).new_and_unread_results(limit: false)
|
||||
expect(topics).to match_array([new_topic, unread_topic])
|
||||
end
|
||||
end
|
||||
|
||||
context "when tag" do
|
||||
fab!(:tag) { Fabricate(:tag) }
|
||||
fab!(:new_topic_2) { Fabricate(:topic) }
|
||||
fab!(:unread_topic_2) { Fabricate(:topic, highest_post_number: 3) }
|
||||
fab!(:topic_user) do
|
||||
Fabricate(
|
||||
:topic_user,
|
||||
topic: unread_topic_2,
|
||||
user: user,
|
||||
notification_level: NotificationLevels.topic_levels[:tracking],
|
||||
last_read_post_number: 1,
|
||||
)
|
||||
end
|
||||
fab!(:topic_tag) { Fabricate(:topic_tag, topic: new_topic_2, tag: tag) }
|
||||
fab!(:topic_tag_2) { Fabricate(:topic_tag, topic: unread_topic_2, tag: tag) }
|
||||
|
||||
it "dismisses new topics, unread posts and untrack for specific tag" do
|
||||
topics = TopicQuery.new(user).new_and_unread_results(limit: false)
|
||||
expect(topics).to match_array([new_topic, new_topic_2, unread_topic, unread_topic_2])
|
||||
|
||||
put "/topics/reset-new.json",
|
||||
params: {
|
||||
dismiss_topics: true,
|
||||
dismiss_posts: true,
|
||||
untrack: true,
|
||||
tag_id: tag.name,
|
||||
}
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.parsed_body["topic_ids"]).to eq([new_topic_2.id, unread_topic_2.id])
|
||||
|
||||
topics = TopicQuery.new(user).new_and_unread_results(limit: false)
|
||||
expect(topics).to match_array([new_topic, unread_topic])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#feature_stats" do
|
||||
|
|
23
spec/system/dismiss_topics_spec.rb
Normal file
23
spec/system/dismiss_topics_spec.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
describe "Filtering topics", type: :system, js: true do
|
||||
fab!(:user) { Fabricate(:user) }
|
||||
let(:topic_list) { PageObjects::Components::TopicList.new }
|
||||
let(:dismiss_new_modal) { PageObjects::Modals::DismissNew.new }
|
||||
fab!(:group) { Fabricate(:group).tap { |g| g.add(user) } }
|
||||
fab!(:topic) { Fabricate(:topic) }
|
||||
|
||||
before { SiteSetting.experimental_new_new_view_groups = group.id }
|
||||
|
||||
it "displays confirmation modal with preselected options" do
|
||||
sign_in(user)
|
||||
|
||||
visit("/new")
|
||||
|
||||
expect(topic_list).to have_topic(topic)
|
||||
find(".dismiss-read").click
|
||||
expect(dismiss_new_modal).to have_dismiss_topics_checked
|
||||
expect(dismiss_new_modal).to have_dismiss_posts_checked
|
||||
expect(dismiss_new_modal).to have_untrack_unchecked
|
||||
end
|
||||
end
|
19
spec/system/page_objects/modals/dismiss_new.rb
Normal file
19
spec/system/page_objects/modals/dismiss_new.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module PageObjects
|
||||
module Modals
|
||||
class DismissNew < PageObjects::Modals::Base
|
||||
def has_dismiss_topics_checked?
|
||||
find(".dismiss-topics label").has_checked_field?
|
||||
end
|
||||
|
||||
def has_dismiss_posts_checked?
|
||||
find(".dismiss-posts label").has_checked_field?
|
||||
end
|
||||
|
||||
def has_untrack_unchecked?
|
||||
find(".untrack label").has_no_checked_field?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue
Block a user