mirror of https://github.com/zulip/zulip.git
compose: Add banner for unmuting the muted topic a message is sent to.
We add a new banner informing the user if and when they send a message to a muted topic / stream. It also has a button to unmute the topic. Fixes: #24246.
This commit is contained in:
parent
ff8d209807
commit
9f2ef69c71
|
@ -39,6 +39,7 @@ import * as transmit from "./transmit";
|
|||
import * as ui_report from "./ui_report";
|
||||
import * as upload from "./upload";
|
||||
import {user_settings} from "./user_settings";
|
||||
import * as user_topics from "./user_topics";
|
||||
import * as util from "./util";
|
||||
import * as zcommand from "./zcommand";
|
||||
|
||||
|
@ -515,6 +516,28 @@ export function initialize() {
|
|||
},
|
||||
);
|
||||
|
||||
$("#compose_banners").on(
|
||||
"click",
|
||||
`.${CSS.escape(
|
||||
compose_banner.CLASSNAMES.unmute_topic_notification,
|
||||
)} .compose_banner_action_button`,
|
||||
(event) => {
|
||||
event.preventDefault();
|
||||
|
||||
const $target = $(event.target).parents(".compose_banner");
|
||||
const stream_id = Number.parseInt($target.attr("data-stream-id"), 10);
|
||||
const topic_name = $target.attr("data-topic-name");
|
||||
|
||||
user_topics.set_user_topic_visibility_policy(
|
||||
stream_id,
|
||||
topic_name,
|
||||
user_topics.all_visibility_policies.UNMUTED,
|
||||
false,
|
||||
true,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
$("#compose_banners").on(
|
||||
"click",
|
||||
`.${CSS.escape(
|
||||
|
|
|
@ -17,9 +17,15 @@ const MESSAGE_SENT_CLASSNAMES = {
|
|||
narrow_to_recipient: "narrow_to_recipient",
|
||||
scheduled_message_banner: "scheduled_message_banner",
|
||||
};
|
||||
// Technically, unmute_topic_notification is a message sent banner, but
|
||||
// it has distinct behavior / look - it has an associated action button,
|
||||
// does not disappear on scroll - so we don't include it here, as it needs
|
||||
// to be handled separately.
|
||||
|
||||
export const CLASSNAMES = {
|
||||
...MESSAGE_SENT_CLASSNAMES,
|
||||
// unmute topic notifications are styled like warnings but have distinct behaviour
|
||||
unmute_topic_notification: "unmute_topic_notification warning-style",
|
||||
// warnings
|
||||
topic_resolved: "topic_resolved",
|
||||
recipient_not_subscribed: "recipient_not_subscribed",
|
||||
|
@ -43,10 +49,13 @@ export const CLASSNAMES = {
|
|||
user_not_subscribed: "user_not_subscribed",
|
||||
};
|
||||
|
||||
export function clear_message_sent_banners(): void {
|
||||
export function clear_message_sent_banners(include_unmute_banner = true): void {
|
||||
for (const classname of Object.values(MESSAGE_SENT_CLASSNAMES)) {
|
||||
$(`#compose_banners .${CSS.escape(classname)}`).remove();
|
||||
}
|
||||
if (include_unmute_banner) {
|
||||
clear_unmute_topic_notifications();
|
||||
}
|
||||
scroll_to_message_banner_message_id = null;
|
||||
}
|
||||
|
||||
|
@ -65,6 +74,10 @@ export function clear_warnings(): void {
|
|||
$(`#compose_banners .${CSS.escape(WARNING)}`).remove();
|
||||
}
|
||||
|
||||
export function clear_unmute_topic_notifications(): void {
|
||||
$(`#compose_banners .${CLASSNAMES.unmute_topic_notification.replaceAll(" ", ".")}`).remove();
|
||||
}
|
||||
|
||||
export function clear_all(): void {
|
||||
$(`#compose_banners`).empty();
|
||||
}
|
||||
|
|
|
@ -198,7 +198,7 @@ export function scroll_finished() {
|
|||
compose_banner.scroll_to_message_banner_message_id,
|
||||
);
|
||||
if ($message_row.length > 0 && !message_viewport.is_message_below_viewport($message_row)) {
|
||||
compose_banner.clear_message_sent_banners();
|
||||
compose_banner.clear_message_sent_banners(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import $ from "jquery";
|
||||
|
||||
import render_message_sent_banner from "../templates/compose_banner/message_sent_banner.hbs";
|
||||
import render_unmute_topic_banner from "../templates/compose_banner/unmute_topic_banner.hbs";
|
||||
|
||||
import * as alert_words from "./alert_words";
|
||||
import * as blueslip from "./blueslip";
|
||||
|
@ -166,6 +167,21 @@ export function is_window_focused() {
|
|||
return window_focused;
|
||||
}
|
||||
|
||||
function notify_unmute(muted_narrow, stream_id, topic_name) {
|
||||
const $unmute_notification = $(
|
||||
render_unmute_topic_banner({
|
||||
muted_narrow,
|
||||
stream_id,
|
||||
topic_name,
|
||||
classname: compose_banner.CLASSNAMES.unmute_topic_notification,
|
||||
banner_type: "",
|
||||
button_text: $t({defaultMessage: "Unmute topic"}),
|
||||
}),
|
||||
);
|
||||
compose_banner.clear_unmute_topic_notifications();
|
||||
$("#compose_banners").append($unmute_notification);
|
||||
}
|
||||
|
||||
export function notify_above_composebox(
|
||||
banner_text,
|
||||
classname,
|
||||
|
@ -182,7 +198,9 @@ export function notify_above_composebox(
|
|||
link_text,
|
||||
}),
|
||||
);
|
||||
compose_banner.clear_message_sent_banners();
|
||||
// We pass in include_unmute_banner as false because we don't want to
|
||||
// clear any unmute_banner associated with this same message.
|
||||
compose_banner.clear_message_sent_banners(false);
|
||||
$("#compose_banners").append($notification);
|
||||
}
|
||||
|
||||
|
@ -559,6 +577,20 @@ function get_message_header(message) {
|
|||
);
|
||||
}
|
||||
|
||||
export function get_muted_narrow(message) {
|
||||
if (
|
||||
message.type === "stream" &&
|
||||
stream_data.is_muted(message.stream_id) &&
|
||||
!user_topics.is_topic_unmuted(message.stream_id, message.topic)
|
||||
) {
|
||||
return "stream";
|
||||
}
|
||||
if (message.type === "stream" && user_topics.is_topic_muted(message.stream_id, message.topic)) {
|
||||
return "topic";
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function get_local_notify_mix_reason(message) {
|
||||
const $row = message_lists.current.get_row(message.id);
|
||||
if ($row.length > 0) {
|
||||
|
@ -567,14 +599,6 @@ export function get_local_notify_mix_reason(message) {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
if (message.type === "stream" && user_topics.is_topic_muted(message.stream_id, message.topic)) {
|
||||
return $t({defaultMessage: "Sent! Your message was sent to a topic you have muted."});
|
||||
}
|
||||
|
||||
if (message.type === "stream" && stream_data.is_muted(message.stream_id)) {
|
||||
return $t({defaultMessage: "Sent! Your message was sent to a stream you have muted."});
|
||||
}
|
||||
|
||||
// offscreen because it is outside narrow
|
||||
// we can only look for these on non-search (can_apply_locally) messages
|
||||
// see also: exports.notify_messages_outside_current_search
|
||||
|
@ -619,6 +643,15 @@ export function notify_local_mixes(messages, need_user_to_scroll) {
|
|||
continue;
|
||||
}
|
||||
|
||||
const muted_narrow = get_muted_narrow(message);
|
||||
if (muted_narrow) {
|
||||
notify_unmute(muted_narrow, message.stream_id, message.topic);
|
||||
// We don't `continue` after showing the unmute banner, allowing multiple
|
||||
// banners (at max 2 including the unmute banner) to be shown at once,
|
||||
// as it's common for the unmute case to occur simultaneously with
|
||||
// another banner's case, like sending a message to another narrow.
|
||||
}
|
||||
|
||||
let banner_text = get_local_notify_mix_reason(message);
|
||||
|
||||
const link_msg_id = message.id;
|
||||
|
@ -728,7 +761,7 @@ export function register_click_handlers() {
|
|||
const message_id = $(e.currentTarget).data("message-id");
|
||||
message_lists.current.select_id(message_id);
|
||||
navigate.scroll_to_selected();
|
||||
compose_banner.clear_message_sent_banners();
|
||||
compose_banner.clear_message_sent_banners(false);
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
},
|
||||
|
|
|
@ -2,6 +2,7 @@ import render_topic_muted from "../templates/topic_muted.hbs";
|
|||
|
||||
import * as blueslip from "./blueslip";
|
||||
import * as channel from "./channel";
|
||||
import * as compose_banner from "./compose_banner";
|
||||
import * as feedback_widget from "./feedback_widget";
|
||||
import {FoldDict} from "./fold_dict";
|
||||
import {$t} from "./i18n";
|
||||
|
@ -75,7 +76,13 @@ export function get_user_topics_for_visibility_policy(visibility_policy) {
|
|||
return topics;
|
||||
}
|
||||
|
||||
export function set_user_topic_visibility_policy(stream_id, topic, visibility_policy, from_hotkey) {
|
||||
export function set_user_topic_visibility_policy(
|
||||
stream_id,
|
||||
topic,
|
||||
visibility_policy,
|
||||
from_hotkey,
|
||||
from_banner,
|
||||
) {
|
||||
const data = {
|
||||
stream_id,
|
||||
topic,
|
||||
|
@ -90,6 +97,10 @@ export function set_user_topic_visibility_policy(stream_id, topic, visibility_po
|
|||
feedback_widget.dismiss();
|
||||
return;
|
||||
}
|
||||
if (from_banner) {
|
||||
compose_banner.clear_unmute_topic_notifications();
|
||||
return;
|
||||
}
|
||||
if (!from_hotkey) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -323,7 +323,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.warning {
|
||||
/* warning and warning-style classes have the same CSS; this is since
|
||||
the warning class has some associated javascript which we do not want
|
||||
for some of the banners, for which we use the warning-style class. */
|
||||
&.warning,
|
||||
&.warning-style {
|
||||
background-color: hsl(50deg 75% 92%);
|
||||
border-color: hsl(38deg 44% 27% / 40%);
|
||||
color: hsl(38deg 44% 27%);
|
||||
|
|
|
@ -226,7 +226,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.warning {
|
||||
&.warning,
|
||||
&.warning-style {
|
||||
background-color: hsl(53deg 100% 11%);
|
||||
border-color: hsl(38deg 44% 60% / 40%);
|
||||
color: hsl(50deg 45% 80%);
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
{{#> compose_banner }}
|
||||
<p>
|
||||
{{#if (eq muted_narrow "stream")}}
|
||||
{{#tr}}Your message was sent to a stream you have muted.{{/tr}}
|
||||
{{else if (eq muted_narrow "topic")}}
|
||||
{{#tr}}Your message was sent to a topic you have muted.{{/tr}}
|
||||
{{/if}}
|
||||
{{#tr}}You will not receive notifications about new messages.{{/tr}}
|
||||
</p>
|
||||
{{/compose_banner}}
|
|
@ -8,7 +8,7 @@ exports.mock_banners = () => {
|
|||
// zjquery doesn't support `remove`, which is used when clearing the compose box.
|
||||
// TODO: improve how we test this so that we don't have to mock things like this.
|
||||
for (const classname of Object.values(compose_banner.CLASSNAMES)) {
|
||||
$(`#compose_banners .${classname}`).remove = () => {};
|
||||
$(`#compose_banners .${classname.replaceAll(" ", ".")}`).remove = () => {};
|
||||
}
|
||||
$("#compose_banners .warning").remove = () => {};
|
||||
$("#compose_banners .error").remove = () => {};
|
||||
|
|
Loading…
Reference in New Issue