Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

left_sidebar: Add Alerts View to the left sidebar. #28858

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions api_docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ format used by the Zulip server that they are interacting with.

## Changes in Zulip 9.0

**Feature level 244**

* [`POST /register`](/api/register-queue):
Added a new property - `alerts` to the `unread_msgs`, which is an
array that includes message ids of all the messages which contain alert
words set by the user.
* [`GET /events`](/api/get-events):
Added an `has_alert_words` flag which indicates whether a message includes
any of the alert words set by the user or not.

**Feature level 243**

* [`POST /register`](/api/register-queue), [`GET
Expand Down
12 changes: 10 additions & 2 deletions web/src/filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,9 @@ export class Filter {
if (_.isEqual(term_types, ["is-starred"])) {
return true;
}
if (_.isEqual(term_types, ["is-alerted"])) {
return true;
}
if (_.isEqual(term_types, ["streams-public"])) {
return true;
}
Expand Down Expand Up @@ -876,6 +879,8 @@ export class Filter {
return "/#narrow/is/starred";
case "is-mentioned":
return "/#narrow/is/mentioned";
case "is-alerted":
return "/#narrow/is/alerted";
case "streams-public":
return "/#narrow/streams/public";
case "dm":
Expand Down Expand Up @@ -932,6 +937,9 @@ export class Filter {
case "is-resolved":
icon = "check";
break;
case "is-alerted":
zulip_icon = "preview";
break;
default:
icon = undefined;
break;
Expand Down Expand Up @@ -1013,11 +1021,11 @@ export class Filter {
return $t({defaultMessage: "All direct messages"});
case "is-resolved":
return $t({defaultMessage: "Topics marked as resolved"});
case "is-alerted":
return $t({defaultMessage: "Alerted messages"});
// These cases return false for is_common_narrow, and therefore are not
// formatted in the message view header. They are used in narrow.js to
// update the browser title.
case "is-alerted":
return $t({defaultMessage: "Alerted messages"});
case "is-unread":
return $t({defaultMessage: "Unread messages"});
}
Expand Down
42 changes: 36 additions & 6 deletions web/src/left_sidebar_navigation_area.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import $ from "jquery";

import * as alert_words from "./alert_words";
import type {Filter} from "./filter";
import {localstorage} from "./localstorage";
import {page_params} from "./page_params";
Expand Down Expand Up @@ -51,6 +52,16 @@ export function update_scheduled_messages_row(): void {
ui_util.update_unread_count_in_dom($scheduled_li, count);
}

export function update_alert_messages_row(): void {
const $alerted_li = $(".top_left_alerts");
const alert_words_set = alert_words.get_word_list().length > 0;
if (alert_words_set) {
$alerted_li.show();
} else {
$alerted_li.hide();
}
}

export function update_dom_with_unread_counts(
counts: unread.FullUnreadCountsData,
skip_animations: boolean,
Expand All @@ -59,11 +70,13 @@ export function update_dom_with_unread_counts(

// mentioned/home views have simple integer counts
const $mentioned_li = $(".top_left_mentions");
const $alerted_li = $(".top_left_alerts");
const $home_view_li = $(".selected-home-view");
const $streams_header = $("#streams_header");
const $back_to_streams = $("#topics_header");

ui_util.update_unread_count_in_dom($mentioned_li, counts.mentioned_message_count);
ui_util.update_unread_count_in_dom($alerted_li, counts.alert_message_count);
ui_util.update_unread_count_in_dom($home_view_li, counts.home_unread_messages);
ui_util.update_unread_count_in_dom($streams_header, counts.stream_unread_messages);
ui_util.update_unread_count_in_dom($back_to_streams, counts.stream_unread_messages);
Expand All @@ -84,6 +97,7 @@ function deselect_top_left_corner_items(): void {
remove($(".top_left_all_messages"));
remove($(".top_left_starred_messages"));
remove($(".top_left_mentions"));
remove($(".top_left_alerts"));
remove($(".top_left_recent_view"));
remove($(".top_left_inbox"));
}
Expand All @@ -106,12 +120,26 @@ export function handle_narrow_activated(filter: Filter): void {
ops = filter.operands("is");
if (ops.length >= 1) {
filter_name = ops[0];
if (filter_name === "starred") {
$filter_li = $(".top_left_starred_messages");
$filter_li.addClass("active-filter");
} else if (filter_name === "mentioned") {
$filter_li = $(".top_left_mentions");
$filter_li.addClass("active-filter");
switch (filter_name) {
case "starred": {
$filter_li = $(".top_left_starred_messages");
$filter_li.addClass("active-filter");

break;
}
case "mentioned": {
$filter_li = $(".top_left_mentions");
$filter_li.addClass("active-filter");

break;
}
case "alerted": {
$filter_li = $(".top_left_alerts");
$filter_li.addClass("active-filter");

break;
}
// No default
}
}
}
Expand Down Expand Up @@ -230,6 +258,8 @@ export function handle_home_view_changed(new_home_view: string): void {

export function initialize(): void {
update_scheduled_messages_row();
update_alert_messages_row();

restore_views_state();

$("body").on(
Expand Down
34 changes: 33 additions & 1 deletion web/src/left_sidebar_navigation_area_popovers.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import $ from "jquery";

import render_drafts_sidebar_actions from "../templates/drafts_sidebar_action.hbs";
import render_left_sidebar_alerts_view_popover from "../templates/left_sidebar_alerts_view_popover.hbs";
import render_left_sidebar_all_messages_popover from "../templates/popovers/left_sidebar_all_messages_popover.hbs";
import render_left_sidebar_condensed_views_popover from "../templates/popovers/left_sidebar_condensed_views_popover.hbs";
import render_left_sidebar_inbox_popover from "../templates/popovers/left_sidebar_inbox_popover.hbs";
import render_left_sidebar_recent_view_popover from "../templates/popovers/left_sidebar_recent_view_popover.hbs";
import render_starred_messages_sidebar_actions from "../templates/starred_messages_sidebar_actions.hbs";

import * as alert_words from "./alert_words";
import * as channel from "./channel";
import * as drafts from "./drafts";
import * as popover_menus from "./popover_menus";
Expand All @@ -16,6 +18,7 @@ import * as settings_config from "./settings_config";
import * as starred_messages from "./starred_messages";
import * as starred_messages_ui from "./starred_messages_ui";
import * as ui_util from "./ui_util";
import {get_counts} from "./unread";
import * as unread_ops from "./unread_ops";
import {user_settings} from "./user_settings";

Expand Down Expand Up @@ -212,24 +215,53 @@ export function initialize() {
},
});

// Alerts popover
popover_menus.register_popover_menu(".alerts-sidebar-menu-icon", {
...popover_menus.left_sidebar_tippy_options,
onMount(instance) {
const $popper = $(instance.popper);

$popper.one("click", "#alert_words_settings", () => {
instance.hide();
});
},
onShow(instance) {
ui_util.show_left_sidebar_menu_icon(instance.reference);
popovers.hide_all();
instance.setContent(ui_util.parse_html(render_left_sidebar_alerts_view_popover()));
},
onHidden(instance) {
instance.destroy();
ui_util.hide_left_sidebar_menu_icon();
},
});

popover_menus.register_popover_menu(".left-sidebar-navigation-menu-icon", {
...popover_menus.left_sidebar_tippy_options,
onShow(instance) {
// Determine at show time whether there are scheduled messages,
// so that Tippy properly calculates the height of the popover
const scheduled_message_count = scheduled_messages.get_count();
const alert_words_set = alert_words.get_word_list().length > 0;
let has_scheduled_messages = false;
if (scheduled_message_count > 0) {
has_scheduled_messages = true;
}
popovers.hide_all();
instance.setContent(
ui_util.parse_html(
render_left_sidebar_condensed_views_popover({has_scheduled_messages}),
render_left_sidebar_condensed_views_popover({
alert_words_set,
has_scheduled_messages,
}),
),
);
},
onMount() {
ui_util.update_unread_count_in_dom(
$(".condensed-views-popover-menu-alerts"),
get_counts().alert_message_count,
);
ui_util.update_unread_count_in_dom(
$(".condensed-views-popover-menu-drafts"),
drafts.draft_model.getDraftCount(),
Expand Down
15 changes: 15 additions & 0 deletions web/src/narrow_banner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,21 @@ function pick_empty_narrow_banner(): NarrowBannerData {
},
),
};
case "alerted":
return {
title: $t({defaultMessage: "You have no messages with alert words."}),
html: $t_html(
{
defaultMessage: "Learn more about alerts <z-link>here</z-link>.",
},
{
"z-link": (content_html) =>
`<a target="_blank" rel="noopener noreferrer" href="/help/dm-mention-alert-notifications">${content_html.join(
"",
)}</a>`,
},
),
};
case "dm":
// You have no direct messages.
if (
Expand Down
1 change: 1 addition & 0 deletions web/src/server_events_dispatch.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export function dispatch_normal_event(event) {
case "alert_words":
alert_words.set_words(event.alert_words);
alert_words_ui.rerender_alert_words_ui();
left_sidebar_navigation_area.update_alert_messages_row();
break;

case "attachment":
Expand Down
36 changes: 36 additions & 0 deletions web/src/unread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ export const unread_mentions_counter = new Set<number>();
export const direct_message_with_mention_count = new Set();
const unread_messages = new Set<number>();

export const unread_alerts_counter = new Set<number>();

// Map with keys of the form "{stream_id}:{topic.toLowerCase()}" and
// values being Sets of message IDs for unread messages mentioning the
// user within that topic. Use `recent_view_util.get_topic_key` to
Expand Down Expand Up @@ -698,6 +700,7 @@ export function process_loaded_messages(
if (message.type === "private") {
process_unread_message({
id: message.id,
alerted: message.alerted,
mentioned: message.mentioned,
mentioned_me_directly: message.mentioned_me_directly,
type: message.type,
Expand All @@ -707,6 +710,7 @@ export function process_loaded_messages(
} else {
process_unread_message({
id: message.id,
alerted: message.alerted,
mentioned: message.mentioned,
mentioned_me_directly: message.mentioned_me_directly,
type: message.type,
Expand All @@ -724,6 +728,7 @@ export function process_loaded_messages(

type UnreadMessageData = {
id: number;
alerted: boolean;
mentioned: boolean;
mentioned_me_directly: boolean;
unread: boolean;
Expand Down Expand Up @@ -762,6 +767,7 @@ export function process_unread_message(message: UnreadMessageData): void {
}

update_message_for_mention(message);
update_message_for_alert(message);
}

export function update_message_for_mention(
Expand Down Expand Up @@ -809,6 +815,27 @@ export function update_message_for_mention(
return false;
}

export function update_message_for_alert(
message: UnreadMessageData,
content_edited = false,
): boolean {
// Returns true if this is a stream message whose content was
// changed, and thus the caller might need to trigger a rerender
// of UI elements displaying whether the message's topic contains
// an unread mention of the user.
if (!message.unread) {
unread_alerts_counter.delete(message.id);
return false;
}
if (message.alerted) {
unread_alerts_counter.add(message.id);
}
if (content_edited && message.type === "stream") {
return true;
}
return false;
}

export function mark_as_read(message_id: number): void {
// We don't need to check anything about the message, since all
// the following methods are cheap and work fine even if message_id
Expand All @@ -821,6 +848,7 @@ export function mark_as_read(message_id: number): void {
remove_message_from_unread_mention_topics(message_id);
unread_topic_counter.delete(message_id);
unread_mentions_counter.delete(message_id);
unread_alerts_counter.delete(message_id);
direct_message_with_mention_count.delete(message_id);
unread_messages.delete(message_id);

Expand All @@ -835,6 +863,7 @@ export function declare_bankruptcy(): void {
unread_direct_message_counter.clear();
unread_topic_counter.clear();
unread_mentions_counter.clear();
unread_alerts_counter.clear();
direct_message_with_mention_count.clear();
unread_messages.clear();
unread_mention_topics.clear();
Expand All @@ -851,6 +880,7 @@ export function get_unread_topics(include_per_topic_latest_msg_id = false): Unre
export type FullUnreadCountsData = {
direct_message_count: number;
mentioned_message_count: number;
alert_message_count: number;
direct_message_with_mention_count: number;
stream_unread_messages: number;
followed_topic_unread_messages_count: number;
Expand All @@ -872,6 +902,7 @@ export function get_counts(): FullUnreadCountsData {
return {
direct_message_count: pm_res.total_count,
mentioned_message_count: unread_mentions_counter.size,
alert_message_count: unread_alerts_counter.size,
direct_message_with_mention_count: direct_message_with_mention_count.size,
stream_unread_messages: topic_res.stream_unread_messages,
followed_topic_unread_messages_count: topic_res.followed_topic_unread_messages,
Expand Down Expand Up @@ -1041,6 +1072,7 @@ type UnreadMessagesParams = {
streams: UnreadStreamInfo[];
huddles: UnreadHuddleInfo[];
mentions: number[];
alerts: number[];
count: number;
old_unreads_missing: boolean;
};
Expand All @@ -1061,6 +1093,10 @@ export function initialize(params: UnreadMessagesParams): void {
}
clear_and_populate_unread_mention_topics();

for (const message_id of unread_msgs.alerts) {
unread_alerts_counter.add(message_id);
}

for (const obj of unread_msgs.huddles) {
for (const message_id of obj.unread_message_ids) {
unread_messages.add(message_id);
Expand Down
1 change: 1 addition & 0 deletions web/src/unread_ops.js
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ export function process_unread_messages_event({message_ids, message_details}) {
unread.process_unread_message({
id: message_id,
mentioned: message_info.mentioned,
alerted: message_info.alert,
mentioned_me_directly,
stream_id: message_info.stream_id,
topic: message_info.topic,
Expand Down
Loading
Loading