diff --git a/frontend_tests/node_tests/starred_messages.js b/frontend_tests/node_tests/starred_messages.js index 8bd2443806..84d03a96d0 100644 --- a/frontend_tests/node_tests/starred_messages.js +++ b/frontend_tests/node_tests/starred_messages.js @@ -9,7 +9,9 @@ const {run_test} = require("../zjsunit/test"); const page_params = set_global("page_params", {}); zrequire("timerender"); +const message_store = zrequire("message_store"); const starred_messages = zrequire("starred_messages"); +const stream_popover = zrequire("stream_popover"); const top_left_corner = zrequire("top_left_corner"); run_test("add starred", (override) => { @@ -38,6 +40,48 @@ run_test("remove starred", (override) => { assert.equal(starred_messages.get_count(), 1); }); +run_test("get starred ids in topic", () => { + for (const id of [1, 2, 3, 4, 5]) { + starred_messages.starred_ids.add(id); + } + + assert.deepEqual( + starred_messages.get_starred_message_ids_in_topic(undefined, "topic name"), + [], + ); + assert.deepEqual(starred_messages.get_starred_message_ids_in_topic(3, undefined), []); + + // id: 1 isn't inserted, to test handling the case + // when message_store.get() returns undefined + message_store.create_mock_message({ + id: 2, + type: "private", + }); + message_store.create_mock_message({ + // Different stream + id: 3, + type: "stream", + stream_id: 19, + topic: "topic", + }); + message_store.create_mock_message({ + // Different topic + id: 4, + type: "stream", + stream_id: 20, + topic: "some other topic", + }); + message_store.create_mock_message({ + // Correct match + id: 5, + type: "stream", + stream_id: 20, + topic: "topic", + }); + + assert.deepEqual(starred_messages.get_starred_message_ids_in_topic(20, "topic"), [5]); +}); + run_test("initialize", (override) => { starred_messages.starred_ids.clear(); for (const id of [1, 2, 3]) { @@ -59,6 +103,7 @@ run_test("rerender_ui", () => { page_params.starred_message_counts = true; with_overrides((override) => { const stub = make_stub(); + override(stream_popover, "hide_topic_popover", () => {}); override(top_left_corner, "update_starred_count", stub.f); starred_messages.rerender_ui(); assert.equal(stub.num_calls, 1); @@ -69,6 +114,7 @@ run_test("rerender_ui", () => { page_params.starred_message_counts = false; with_overrides((override) => { const stub = make_stub(); + override(stream_popover, "hide_topic_popover", () => {}); override(top_left_corner, "update_starred_count", stub.f); starred_messages.rerender_ui(); assert.equal(stub.num_calls, 1); diff --git a/static/js/message_flags.js b/static/js/message_flags.js index 54507e57f5..e1fac76cc9 100644 --- a/static/js/message_flags.js +++ b/static/js/message_flags.js @@ -120,3 +120,8 @@ export function unstar_all_messages() { const starred_msg_ids = starred_messages.get_starred_msg_ids(); send_flag_update_for_messages(starred_msg_ids, "starred", "remove"); } + +export function unstar_all_messages_in_topic(stream_id, topic) { + const starred_message_ids = starred_messages.get_starred_message_ids_in_topic(stream_id, topic); + send_flag_update_for_messages(starred_message_ids, "starred", "remove"); +} diff --git a/static/js/starred_messages.js b/static/js/starred_messages.js index b1fe5c7340..f9ac99ce03 100644 --- a/static/js/starred_messages.js +++ b/static/js/starred_messages.js @@ -1,9 +1,11 @@ import $ from "jquery"; import render_confirm_unstar_all_messages from "../templates/confirm_unstar_all_messages.hbs"; +import render_confirm_unstar_all_messages_in_topic from "../templates/confirm_unstar_all_messages_in_topic.hbs"; import * as confirm_dialog from "./confirm_dialog"; import * as message_flags from "./message_flags"; +import * as message_store from "./message_store"; import * as stream_popover from "./stream_popover"; import * as top_left_corner from "./top_left_corner"; @@ -43,6 +45,32 @@ export function get_starred_msg_ids() { return Array.from(starred_ids); } +export function get_starred_message_ids_in_topic(stream_id, topic) { + if (stream_id === undefined || topic === undefined) { + return []; + } + + return Array.from(starred_ids).filter((id) => { + const message = message_store.get(id); + + if (message === undefined) { + // We know the `id` from the initial data fetch from page_params, + // but the message itself hasn't been fetched from the server yet. + // We ignore this message, since we can't check if it belongs to + // the topic, but it could, meaning this implementation isn't + // completely correct. The right way to do this would be to ask the + // backend for starred IDs from the topic. + return false; + } + + return ( + message.type === "stream" && + message.stream_id === stream_id && + message.topic.toLowerCase() === topic.toLowerCase() + ); + }); +} + export function rerender_ui() { let count = get_count(); @@ -51,6 +79,7 @@ export function rerender_ui() { count = 0; } + stream_popover.hide_topic_popover(); top_left_corner.update_starred_count(count); stream_popover.hide_starred_messages_popover(); } @@ -67,3 +96,22 @@ export function confirm_unstar_all_messages() { on_click: message_flags.unstar_all_messages, }); } + +export function confirm_unstar_all_messages_in_topic(stream_id, topic) { + function on_click() { + message_flags.unstar_all_messages_in_topic(stream_id, topic); + } + + const modal_parent = $(".left-sidebar-modal-holder"); + const html_body = render_confirm_unstar_all_messages_in_topic({ + topic, + }); + + confirm_dialog.launch({ + parent: modal_parent, + html_heading: i18n.t("Unstar messages in topic"), + html_body, + html_yes_button: i18n.t("Unstar messages"), + on_click, + }); +} diff --git a/static/js/stream_popover.js b/static/js/stream_popover.js index 9af6890b4f..1e62890727 100644 --- a/static/js/stream_popover.js +++ b/static/js/stream_popover.js @@ -234,6 +234,8 @@ function build_topic_popover(opts) { const is_muted = muting.is_topic_muted(sub.stream_id, topic_name); const can_mute_topic = !is_muted; const can_unmute_topic = is_muted; + const has_starred_messages = + starred_messages.get_starred_message_ids_in_topic(sub.stream_id, topic_name).length > 0; const content = render_topic_sidebar_actions({ stream_name: sub.name, @@ -243,6 +245,7 @@ function build_topic_popover(opts) { can_unmute_topic, is_realm_admin: sub.is_realm_admin, color: sub.color, + has_starred_messages, }); $(elt).popover({ @@ -432,6 +435,19 @@ export function register_stream_handlers() { starred_messages.confirm_unstar_all_messages(); }); + // Unstar all messages in topic + $("body").on("click", ".sidebar-popover-unstar-all-in-topic", (e) => { + e.preventDefault(); + e.stopPropagation(); + const topic_name = $(".sidebar-popover-unstar-all-in-topic").attr("data-topic-name"); + const stream_id = $(".sidebar-popover-unstar-all-in-topic").attr("data-stream-id"); + hide_topic_popover(); + starred_messages.confirm_unstar_all_messages_in_topic( + Number.parseInt(stream_id, 10), + topic_name, + ); + }); + // Toggle displaying starred message count $("body").on("click", "#toggle_display_starred_msg_count", (e) => { hide_starred_messages_popover(); diff --git a/static/templates/confirm_unstar_all_messages_in_topic.hbs b/static/templates/confirm_unstar_all_messages_in_topic.hbs new file mode 100644 index 0000000000..b4b9c35a36 --- /dev/null +++ b/static/templates/confirm_unstar_all_messages_in_topic.hbs @@ -0,0 +1,5 @@ +
+ {{#tr this}} + Are you sure you want to unstar all messages in topic __topic__? This action cannot be undone. + {{/tr}} +
diff --git a/static/templates/topic_sidebar_actions.hbs b/static/templates/topic_sidebar_actions.hbs index 38ebcf3881..3a9f10b91f 100644 --- a/static/templates/topic_sidebar_actions.hbs +++ b/static/templates/topic_sidebar_actions.hbs @@ -34,6 +34,16 @@ {{/if}} + + {{#if has_starred_messages}} +