overlays: Add overlay to display scheduled reminders.

This commit is contained in:
Aman Agrawal
2025-06-28 02:45:51 +05:30
committed by Tim Abbott
parent 25731859b6
commit 4a8d86f151
22 changed files with 368 additions and 0 deletions

View File

@@ -139,6 +139,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1943053 -->
<div id="groups_overlay_container"></div> <div id="groups_overlay_container"></div>
<div id="drafts_table"></div> <div id="drafts_table"></div>
<div id="scheduled_messages_overlay_container"></div> <div id="scheduled_messages_overlay_container"></div>
<div id="reminders-overlay-container"></div>
<div id="settings_overlay_container" class="overlay" data-overlay="settings" aria-hidden="true"> <div id="settings_overlay_container" class="overlay" data-overlay="settings" aria-hidden="true">
</div> </div>
<div id="message-edit-history-overlay-container"></div> <div id="message-edit-history-overlay-container"></div>

View File

@@ -193,6 +193,7 @@ EXEMPT_FILES = make_set(
"web/src/recent_view_ui.ts", "web/src/recent_view_ui.ts",
"web/src/reload.ts", "web/src/reload.ts",
"web/src/reload_setup.js", "web/src/reload_setup.js",
"web/src/reminders_overlay_ui.ts",
"web/src/resize.ts", "web/src/resize.ts",
"web/src/resize_handler.ts", "web/src/resize_handler.ts",
"web/src/rows.ts", "web/src/rows.ts",

View File

@@ -66,6 +66,7 @@ export function is_overlay_hash(hash: string | undefined): boolean {
"search-operators", "search-operators",
"about-zulip", "about-zulip",
"scheduled", "scheduled",
"reminders",
"user", "user",
]; ];
const main_hash = get_hash_category(hash); const main_hash = get_hash_category(hash);

View File

@@ -20,6 +20,7 @@ import {page_params} from "./page_params.ts";
import * as people from "./people.ts"; import * as people from "./people.ts";
import * as popovers from "./popovers.ts"; import * as popovers from "./popovers.ts";
import * as recent_view_ui from "./recent_view_ui.ts"; import * as recent_view_ui from "./recent_view_ui.ts";
import * as reminders_overlay_ui from "./reminders_overlay_ui.ts";
import * as scheduled_messages_overlay_ui from "./scheduled_messages_overlay_ui.ts"; import * as scheduled_messages_overlay_ui from "./scheduled_messages_overlay_ui.ts";
import * as settings from "./settings.ts"; import * as settings from "./settings.ts";
import * as settings_panel_menu from "./settings_panel_menu.ts"; import * as settings_panel_menu from "./settings_panel_menu.ts";
@@ -260,6 +261,7 @@ function do_hashchange_normal(from_reload: boolean, restore_selected_id: boolean
case "#settings": case "#settings":
case "#about-zulip": case "#about-zulip":
case "#scheduled": case "#scheduled":
case "#reminders":
blueslip.error("overlay logic skipped for: " + hash[0]); blueslip.error("overlay logic skipped for: " + hash[0]);
break; break;
default: default:
@@ -504,6 +506,11 @@ function do_hashchange_overlay(old_hash: string | undefined): void {
return; return;
} }
if (base === "reminders") {
reminders_overlay_ui.launch();
return;
}
if (base === "user") { if (base === "user") {
const user_id = Number.parseInt(hash_parser.get_current_hash_section(), 10); const user_id = Number.parseInt(hash_parser.get_current_hash_section(), 10);
if (!people.is_known_user_id(user_id)) { if (!people.is_known_user_id(user_id)) {

View File

@@ -47,6 +47,7 @@ import * as reactions from "./reactions.ts";
import * as read_receipts from "./read_receipts.ts"; import * as read_receipts from "./read_receipts.ts";
import * as recent_view_ui from "./recent_view_ui.ts"; import * as recent_view_ui from "./recent_view_ui.ts";
import * as recent_view_util from "./recent_view_util.ts"; import * as recent_view_util from "./recent_view_util.ts";
import * as reminders_overlay_ui from "./reminders_overlay_ui.ts";
import * as scheduled_messages_overlay_ui from "./scheduled_messages_overlay_ui.ts"; import * as scheduled_messages_overlay_ui from "./scheduled_messages_overlay_ui.ts";
import * as search from "./search.ts"; import * as search from "./search.ts";
import {message_edit_history_visibility_policy_values} from "./settings_config.ts"; import {message_edit_history_visibility_policy_values} from "./settings_config.ts";
@@ -616,6 +617,11 @@ export function process_enter_key(e) {
return true; return true;
} }
if (overlays.reminders_open()) {
reminders_overlay_ui.handle_keyboard_events("enter");
return true;
}
// Transfer the enter keypress from button to the `<i>` tag inside // Transfer the enter keypress from button to the `<i>` tag inside
// it since it is the trigger for the popover. <button> is already used // it since it is the trigger for the popover. <button> is already used
// to trigger the tooltip so it cannot be used to trigger the popover. // to trigger the tooltip so it cannot be used to trigger the popover.
@@ -872,6 +878,10 @@ export function process_hotkey(e, hotkey) {
scheduled_messages_overlay_ui.handle_keyboard_events(event_name); scheduled_messages_overlay_ui.handle_keyboard_events(event_name);
return true; return true;
} }
if (overlays.reminders_open()) {
reminders_overlay_ui.handle_keyboard_events(event_name);
return true;
}
if (overlays.message_edit_history_open()) { if (overlays.message_edit_history_open()) {
message_edit_history.handle_keyboard_events(event_name); message_edit_history.handle_keyboard_events(event_name);
return true; return true;

View File

@@ -3,6 +3,7 @@ import _ from "lodash";
import type {Filter} from "./filter.ts"; import type {Filter} from "./filter.ts";
import {localstorage} from "./localstorage.ts"; import {localstorage} from "./localstorage.ts";
import * as message_reminder from "./message_reminder.ts";
import {page_params} from "./page_params.ts"; import {page_params} from "./page_params.ts";
import * as people from "./people.ts"; import * as people from "./people.ts";
import * as resize from "./resize.ts"; import * as resize from "./resize.ts";
@@ -59,6 +60,17 @@ export function update_scheduled_messages_row(): void {
ui_util.update_unread_count_in_dom($scheduled_li, count); ui_util.update_unread_count_in_dom($scheduled_li, count);
} }
export function update_reminders_row(): void {
const $reminders_li = $(".top_left_reminders");
const count = message_reminder.get_count();
if (count > 0) {
$reminders_li.addClass("show-with-reminders");
} else {
$reminders_li.removeClass("show-with-reminders");
}
ui_util.update_unread_count_in_dom($reminders_li, count);
}
export function update_dom_with_unread_counts( export function update_dom_with_unread_counts(
counts: unread.FullUnreadCountsData, counts: unread.FullUnreadCountsData,
skip_animations: boolean, skip_animations: boolean,
@@ -251,6 +263,7 @@ export function handle_home_view_changed(new_home_view: string): void {
} }
export function initialize(): void { export function initialize(): void {
update_reminders_row();
update_scheduled_messages_row(); update_scheduled_messages_row();
restore_views_state(); restore_views_state();

View File

@@ -1,11 +1,17 @@
import $ from "jquery"; import $ from "jquery";
import type {z} from "zod";
import * as channel from "./channel.ts"; import * as channel from "./channel.ts";
import * as feedback_widget from "./feedback_widget.ts"; import * as feedback_widget from "./feedback_widget.ts";
import {$t} from "./i18n.ts"; import {$t} from "./i18n.ts";
import type {StateData, reminder_schema} from "./state_data.ts";
import * as timerender from "./timerender.ts"; import * as timerender from "./timerender.ts";
import * as ui_report from "./ui_report.ts"; import * as ui_report from "./ui_report.ts";
export type Reminder = z.infer<typeof reminder_schema>;
export const reminders_by_id = new Map<number, Reminder>();
export function set_message_reminder(send_at_time: number, message_id: number): void { export function set_message_reminder(send_at_time: number, message_id: number): void {
channel.post({ channel.post({
url: "/json/reminders", url: "/json/reminders",
@@ -39,3 +45,30 @@ export function set_message_reminder(send_at_time: number, message_id: number):
}, },
}); });
} }
export function add_reminders(reminders: Reminder[]): void {
for (const reminder of reminders) {
reminders_by_id.set(reminder.reminder_id, reminder);
}
}
export function initialize(reminders_params: StateData["reminders"]): void {
add_reminders(reminders_params.reminders);
}
export function remove_reminder(reminder_id: number): void {
if (reminders_by_id.has(reminder_id)) {
reminders_by_id.delete(reminder_id);
}
}
export function delete_reminder(reminder_id: number, success?: () => void): void {
void channel.del({
url: "/json/reminders/" + reminder_id,
success,
});
}
export function get_count(): number {
return reminders_by_id.size;
}

View File

@@ -73,6 +73,10 @@ export function scheduled_messages_open(): boolean {
return open_overlay_name === "scheduled"; return open_overlay_name === "scheduled";
} }
export function reminders_open(): boolean {
return open_overlay_name === "reminders";
}
export function message_edit_history_open(): boolean { export function message_edit_history_open(): boolean {
return open_overlay_name === "message_edit_history"; return open_overlay_name === "message_edit_history";
} }

View File

@@ -0,0 +1,131 @@
import $ from "jquery";
import assert from "minimalistic-assert";
import render_reminder_list from "../templates/reminder_list.hbs";
import render_reminders_overlay from "../templates/reminders_overlay.hbs";
import * as browser_history from "./browser_history.ts";
import * as message_reminder from "./message_reminder.ts";
import type {Reminder} from "./message_reminder.ts";
import * as messages_overlay_ui from "./messages_overlay_ui.ts";
import * as overlays from "./overlays.ts";
import * as timerender from "./timerender.ts";
type ReminderRenderContext = Reminder & {
formatted_send_at_time: string;
};
export const keyboard_handling_context = {
get_items_ids() {
const reminders_ids = [];
const sorted_reminders = sort_reminders(message_reminder.reminders_by_id);
for (const reminder of sorted_reminders) {
reminders_ids.push(reminder.reminder_id.toString());
}
return reminders_ids;
},
on_enter() {
// TODO: Allow editing reminder.
return;
},
on_delete() {
const focused_element_id = messages_overlay_ui.get_focused_element_id(this);
if (focused_element_id === undefined) {
return;
}
const $focused_row = messages_overlay_ui.row_with_focus(this);
messages_overlay_ui.focus_on_sibling_element(this);
// We need to have a super responsive UI feedback here, so we remove the row from the DOM manually
$focused_row.remove();
message_reminder.delete_reminder(Number.parseInt(focused_element_id, 10));
},
items_container_selector: "reminders-container",
items_list_selector: "reminders-list",
row_item_selector: "reminder-row",
box_item_selector: "reminder-info-box",
id_attribute_name: "data-reminder-id",
};
function sort_reminders(reminders: Map<number, Reminder>): Reminder[] {
const sorted_reminders = [...reminders.values()].sort(
(reminder1, reminder2) =>
reminder1.scheduled_delivery_timestamp - reminder2.scheduled_delivery_timestamp,
);
return sorted_reminders;
}
export function handle_keyboard_events(event_key: string): void {
messages_overlay_ui.modals_handle_events(event_key, keyboard_handling_context);
}
function format(reminders: Map<number, Reminder>): ReminderRenderContext[] {
const formatted_reminders = [];
const sorted_reminders = sort_reminders(reminders);
for (const reminder of sorted_reminders) {
const time = new Date(reminder.scheduled_delivery_timestamp * 1000);
const formatted_send_at_time = timerender.get_full_datetime(time, "time");
const reminder_render_context = {
...reminder,
formatted_send_at_time,
};
formatted_reminders.push(reminder_render_context);
}
return formatted_reminders;
}
export function launch(): void {
$("#reminders-overlay-container").html(render_reminders_overlay());
overlays.open_overlay({
name: "reminders",
$overlay: $("#reminders-overlay"),
on_close() {
browser_history.exit_overlay();
},
});
const rendered_list = render_reminder_list({
reminders_data: format(message_reminder.reminders_by_id),
});
const $messages_list = $("#reminders-overlay .overlay-messages-list");
$messages_list.append($(rendered_list));
const first_element_id = keyboard_handling_context.get_items_ids()[0];
messages_overlay_ui.set_initial_element(first_element_id, keyboard_handling_context);
}
export function rerender(): void {
if (!overlays.reminders_open()) {
return;
}
const rendered_list = render_reminder_list({
reminders_data: format(message_reminder.reminders_by_id),
});
const $messages_list = $("#reminders-overlay .overlay-messages-list");
$messages_list.find(".reminder-row").remove();
$messages_list.append($(rendered_list));
}
export function remove_reminder_id(reminder_id: number): void {
if (overlays.reminders_open()) {
$(`#reminders-overlay .reminder-row[data-reminder-id=${reminder_id}]`).remove();
}
}
export function initialize(): void {
$("body").on("click", ".reminder-row .delete-overlay-message", (e) => {
const scheduled_msg_id = $(e.currentTarget)
.closest(".reminder-row")
.attr("data-reminder-id");
assert(scheduled_msg_id !== undefined);
message_reminder.delete_reminder(Number.parseInt(scheduled_msg_id, 10));
e.stopPropagation();
e.preventDefault();
});
$("body").on("focus", ".reminder-info-box", function (this: HTMLElement) {
messages_overlay_ui.activate_element(this, keyboard_handling_context);
});
}

View File

@@ -30,6 +30,7 @@ import * as message_edit from "./message_edit.ts";
import * as message_events from "./message_events.ts"; import * as message_events from "./message_events.ts";
import * as message_lists from "./message_lists.ts"; import * as message_lists from "./message_lists.ts";
import * as message_live_update from "./message_live_update.ts"; import * as message_live_update from "./message_live_update.ts";
import * as message_reminder from "./message_reminder.ts";
import * as message_store from "./message_store.ts"; import * as message_store from "./message_store.ts";
import * as message_view from "./message_view.ts"; import * as message_view from "./message_view.ts";
import * as muted_users_ui from "./muted_users_ui.ts"; import * as muted_users_ui from "./muted_users_ui.ts";
@@ -47,6 +48,7 @@ import * as realm_playground from "./realm_playground.ts";
import {realm_user_settings_defaults} from "./realm_user_settings_defaults.ts"; import {realm_user_settings_defaults} from "./realm_user_settings_defaults.ts";
import * as recent_view_ui from "./recent_view_ui.ts"; import * as recent_view_ui from "./recent_view_ui.ts";
import * as reload from "./reload.ts"; import * as reload from "./reload.ts";
import * as reminders_overlay_ui from "./reminders_overlay_ui.ts";
import * as saved_snippets from "./saved_snippets.ts"; import * as saved_snippets from "./saved_snippets.ts";
import * as saved_snippets_ui from "./saved_snippets_ui.ts"; import * as saved_snippets_ui from "./saved_snippets_ui.ts";
import * as scheduled_messages from "./scheduled_messages.ts"; import * as scheduled_messages from "./scheduled_messages.ts";
@@ -642,6 +644,24 @@ export function dispatch_normal_event(event) {
} }
break; break;
case "reminders":
switch (event.op) {
case "add": {
message_reminder.add_reminders(event.reminders);
reminders_overlay_ui.rerender();
left_sidebar_navigation_area.update_reminders_row();
break;
}
case "remove": {
message_reminder.remove_reminder(event.reminder_id);
reminders_overlay_ui.remove_reminder_id(event.reminder_id);
left_sidebar_navigation_area.update_reminders_row();
break;
}
// No default
}
break;
case "stream": case "stream":
switch (event.op) { switch (event.op) {
case "update": case "update":

View File

@@ -63,6 +63,17 @@ export const scheduled_message_schema = z
]), ]),
); );
export const reminder_schema = z.object({
reminder_id: z.number(),
type: z.literal("private"),
to: z.array(z.number()),
content: z.string(),
rendered_content: z.string(),
scheduled_delivery_timestamp: z.number(),
failed: z.boolean(),
reminder_target_message_id: z.number(),
});
export const profile_datum_schema = z.object({ export const profile_datum_schema = z.object({
value: z.string(), value: z.string(),
rendered_value: z.string().nullish(), rendered_value: z.string().nullish(),
@@ -559,6 +570,7 @@ export const state_data_schema = z
.object({scheduled_messages: z.array(scheduled_message_schema)}) .object({scheduled_messages: z.array(scheduled_message_schema)})
.transform((scheduled_messages) => ({scheduled_messages})), .transform((scheduled_messages) => ({scheduled_messages})),
) )
.and(z.object({reminders: z.array(reminder_schema)}).transform((reminders) => ({reminders})))
.and( .and(
z z
.object({ .object({

View File

@@ -73,6 +73,7 @@ import * as message_fetch from "./message_fetch.ts";
import * as message_list_hover from "./message_list_hover.ts"; import * as message_list_hover from "./message_list_hover.ts";
import * as message_list_tooltips from "./message_list_tooltips.ts"; import * as message_list_tooltips from "./message_list_tooltips.ts";
import * as message_lists from "./message_lists.ts"; import * as message_lists from "./message_lists.ts";
import * as message_reminder from "./message_reminder.ts";
import * as message_scroll from "./message_scroll.ts"; import * as message_scroll from "./message_scroll.ts";
import * as message_view from "./message_view.ts"; import * as message_view from "./message_view.ts";
import * as message_view_header from "./message_view_header.ts"; import * as message_view_header from "./message_view_header.ts";
@@ -103,6 +104,7 @@ import * as realm_playground from "./realm_playground.ts";
import * as realm_user_settings_defaults from "./realm_user_settings_defaults.ts"; import * as realm_user_settings_defaults from "./realm_user_settings_defaults.ts";
import * as recent_view_ui from "./recent_view_ui.ts"; import * as recent_view_ui from "./recent_view_ui.ts";
import * as reload_setup from "./reload_setup.js"; import * as reload_setup from "./reload_setup.js";
import * as reminders_overlay_ui from "./reminders_overlay_ui.ts";
import * as resize_handler from "./resize_handler.ts"; import * as resize_handler from "./resize_handler.ts";
import * as saved_snippets from "./saved_snippets.ts"; import * as saved_snippets from "./saved_snippets.ts";
import * as scheduled_messages from "./scheduled_messages.ts"; import * as scheduled_messages from "./scheduled_messages.ts";
@@ -452,7 +454,9 @@ export async function initialize_everything(state_data) {
left_sidebar_tooltips.initialize(); left_sidebar_tooltips.initialize();
// This populates data for scheduled messages. // This populates data for scheduled messages.
scheduled_messages.initialize(state_data.scheduled_messages); scheduled_messages.initialize(state_data.scheduled_messages);
message_reminder.initialize(state_data.reminders);
scheduled_messages_ui.initialize(); scheduled_messages_ui.initialize();
reminders_overlay_ui.initialize();
popover_menus.initialize(); popover_menus.initialize();
left_sidebar_navigation_area_popovers.initialize(); left_sidebar_navigation_area_popovers.initialize();
user_topic_popover.initialize(); user_topic_popover.initialize();

View File

@@ -822,9 +822,11 @@ li.active-sub-filter {
} }
/* Don't show the scheduled messages item... */ /* Don't show the scheduled messages item... */
li.top_left_reminders,
li.top_left_scheduled_messages { li.top_left_scheduled_messages {
display: none; display: none;
/* ...unless there are scheduled messages to show. */ /* ...unless there are scheduled messages to show. */
&.show-with-reminders,
&.show-with-scheduled-messages { &.show-with-scheduled-messages {
/* Use display: grid to preserve the grid /* Use display: grid to preserve the grid
layout when visible. */ layout when visible. */

View File

@@ -1,3 +1,4 @@
#reminders-overlay-container,
#scheduled_messages_overlay_container { #scheduled_messages_overlay_container {
.no-overlay-messages { .no-overlay-messages {
display: none; display: none;
@@ -14,3 +15,7 @@
font-style: italic; font-style: italic;
color: hsl(0deg 0% 53%); color: hsl(0deg 0% 53%);
} }
#reminders-overlay-container .message_content {
cursor: auto;
}

View File

@@ -152,6 +152,16 @@
<span class="unread_count quiet-count"></span> <span class="unread_count quiet-count"></span>
</a> </a>
</li> </li>
<li class="top_left_reminders top_left_row hidden-for-spectators">
<a class="left-sidebar-navigation-label-container tippy-left-sidebar-tooltip" href="#reminders" data-tooltip-template-id="reminders-tooltip-template">
<span class="filter-icon">
<i class="zulip-icon zulip-icon-alarm-clock" aria-hidden="true"></i>
</span>
{{~!-- squash whitespace --~}}
<span class="left-sidebar-navigation-label">{{t 'Reminders' }}</span>
<span class="unread_count quiet-count"></span>
</a>
</li>
</ul> </ul>
</div> </div>

View File

@@ -0,0 +1,27 @@
{{#each reminders_data}}
<div class="reminder-row overlay-message-row" data-reminder-id="{{reminder_id}}">
<div class="reminder-info-box overlay-message-info-box" tabindex="0">
<div class="message_header message_header_private_message">
<div class="message-header-contents">
<div class="message_label_clickable stream_label">
<span class="private_message_header_icon"><i class="zulip-icon zulip-icon-user"></i></span>
<span class="private_message_header_name">{{t "Notification Bot to you" }}</span>
</div>
{{> scheduled_message_stream_pm_common .}}
</div>
</div>
<div class="message_row{{#unless is_stream}} private-message{{/unless}}" role="listitem">
<div class="messagebox">
<div class="messagebox-content">
<div class="message_top_line">
<div class="overlay_message_controls">
{{> ./components/icon_button intent="danger" custom_classes="delete-overlay-message tippy-zulip-delayed-tooltip" icon="trash" data-tooltip-template-id="delete-reminder-tooltip-template" aria-label=(t "Delete") }}
</div>
</div>
<div class="message_content rendered_markdown restore-overlay-message">{{rendered_markdown rendered_content}}</div>
</div>
</div>
</div>
</div>
</div>
{{/each}}

View File

@@ -0,0 +1,17 @@
<div id="reminders-overlay" class="overlay" data-overlay="reminders">
<div class="flex overlay-content">
<div class="overlay-messages-container overlay-container reminders-container">
<div class="overlay-messages-header">
<h1>{{t 'Scheduled reminders' }}</h1>
<div class="exit">
<span class="exit-sign">&times;</span>
</div>
</div>
<div class="reminders-list overlay-messages-list">
<div class="no-overlay-messages">
{{t 'No reminders scheduled.'}}
</div>
</div>
</div>
</div>
</div>

View File

@@ -161,6 +161,12 @@
<div class="tootlip-inner-content views-message-count italic"></div> <div class="tootlip-inner-content views-message-count italic"></div>
</div> </div>
</template> </template>
<template id="reminders-tooltip-template">
<div class="views-tooltip-container" data-view-code="reminders">
<div>{{t 'Reminders'}}</div>
<div class="tootlip-inner-content views-message-count italic"></div>
</div>
</template>
<template id="show-all-direct-messages-template"> <template id="show-all-direct-messages-template">
{{t 'Direct message feed' }} {{t 'Direct message feed' }}
{{tooltip_hotkey_hints "Shift" "P"}} {{tooltip_hotkey_hints "Shift" "P"}}
@@ -253,6 +259,10 @@
{{t 'Delete scheduled message' }} {{t 'Delete scheduled message' }}
{{tooltip_hotkey_hints "Backspace"}} {{tooltip_hotkey_hints "Backspace"}}
</template> </template>
<template id="delete-reminder-tooltip-template">
{{t 'Delete reminder' }}
{{tooltip_hotkey_hints "Backspace"}}
</template>
<template id="create-new-stream-tooltip-template"> <template id="create-new-stream-tooltip-template">
{{t 'Create new channel' }} {{t 'Create new channel' }}
{{tooltip_hotkey_hints "N"}} {{tooltip_hotkey_hints "N"}}

View File

@@ -49,6 +49,8 @@ const realm_icon = mock_esm("../src/realm_icon");
const realm_logo = mock_esm("../src/realm_logo"); const realm_logo = mock_esm("../src/realm_logo");
const realm_playground = mock_esm("../src/realm_playground"); const realm_playground = mock_esm("../src/realm_playground");
const reload = mock_esm("../src/reload"); const reload = mock_esm("../src/reload");
const message_reminder = mock_esm("../src/message_reminder");
const reminders_overlay_ui = mock_esm("../src/reminders_overlay_ui");
const saved_snippets = mock_esm("../src/saved_snippets"); const saved_snippets = mock_esm("../src/saved_snippets");
const saved_snippets_ui = mock_esm("../src/saved_snippets_ui"); const saved_snippets_ui = mock_esm("../src/saved_snippets_ui");
const scheduled_messages = mock_esm("../src/scheduled_messages"); const scheduled_messages = mock_esm("../src/scheduled_messages");
@@ -89,6 +91,7 @@ const submessage = mock_esm("../src/submessage");
mock_esm("../src/left_sidebar_navigation_area", { mock_esm("../src/left_sidebar_navigation_area", {
update_starred_count() {}, update_starred_count() {},
update_scheduled_messages_row() {}, update_scheduled_messages_row() {},
update_reminders_row() {},
handle_home_view_changed() {}, handle_home_view_changed() {},
}); });
const typing_events = mock_esm("../src/typing_events"); const typing_events = mock_esm("../src/typing_events");
@@ -453,6 +456,30 @@ run_test("reaction", ({override}) => {
} }
}); });
run_test("reminders", ({override}) => {
override(reminders_overlay_ui, "rerender", noop);
override(reminders_overlay_ui, "remove_reminder_id", noop);
let event = event_fixtures.reminders__add;
{
const stub = make_stub();
override(message_reminder, "add_reminders", stub.f);
dispatch(event);
assert.equal(stub.num_calls, 1);
const args = stub.get_args("reminders");
assert_same(args.reminders, event.reminders);
}
event = event_fixtures.reminders__remove;
{
const stub = make_stub();
override(message_reminder, "remove_reminder", stub.f);
dispatch(event);
assert.equal(stub.num_calls, 1);
const args = stub.get_args("reminder_id");
assert_same(args.reminder_id, event.reminder_id);
}
});
run_test("scheduled_messages", ({override}) => { run_test("scheduled_messages", ({override}) => {
override(scheduled_messages_overlay_ui, "rerender", noop); override(scheduled_messages_overlay_ui, "rerender", noop);
override(scheduled_messages_overlay_ui, "remove_scheduled_message_id", noop); override(scheduled_messages_overlay_ui, "remove_scheduled_message_id", noop);

View File

@@ -67,6 +67,7 @@ const overlays = mock_esm("../src/overlays", {
lightbox_open: () => false, lightbox_open: () => false,
drafts_open: () => false, drafts_open: () => false,
scheduled_messages_open: () => false, scheduled_messages_open: () => false,
reminders_open: () => false,
info_overlay_open: () => false, info_overlay_open: () => false,
message_edit_history_open: () => false, message_edit_history_open: () => false,
}); });

View File

@@ -14,6 +14,9 @@ const scheduled_messages = mock_esm("../src/scheduled_messages");
scheduled_messages.get_count = () => 555; scheduled_messages.get_count = () => 555;
const message_reminder = mock_esm("../src/message_reminder");
message_reminder.get_count = () => 888;
const {Filter} = zrequire("../src/filter"); const {Filter} = zrequire("../src/filter");
const left_sidebar_navigation_area = zrequire("left_sidebar_navigation_area"); const left_sidebar_navigation_area = zrequire("left_sidebar_navigation_area");
@@ -116,6 +119,8 @@ run_test("update_count_in_dom", () => {
make_elem($(".top_left_scheduled_messages"), "<scheduled-count>"); make_elem($(".top_left_scheduled_messages"), "<scheduled-count>");
make_elem($(".top_left_reminders"), "<reminders-count>");
make_elem($("#streams_header"), "<stream-count>"); make_elem($("#streams_header"), "<stream-count>");
make_elem($("#topics_header"), "<topics-count>"); make_elem($("#topics_header"), "<topics-count>");
@@ -129,18 +134,22 @@ run_test("update_count_in_dom", () => {
assert.equal($("<home-count>").text(), "333"); assert.equal($("<home-count>").text(), "333");
assert.equal($("<starred-count>").text(), "444"); assert.equal($("<starred-count>").text(), "444");
assert.equal($("<scheduled-count>").text(), "555"); assert.equal($("<scheduled-count>").text(), "555");
assert.equal($("<reminders-count>").text(), "888");
assert.equal($("<stream-count>").text(), "666"); assert.equal($("<stream-count>").text(), "666");
assert.equal($("<topics-count>").text(), "666"); assert.equal($("<topics-count>").text(), "666");
counts.mentioned_message_count = 0; counts.mentioned_message_count = 0;
scheduled_messages.get_count = () => 0; scheduled_messages.get_count = () => 0;
message_reminder.get_count = () => 0;
left_sidebar_navigation_area.update_dom_with_unread_counts(counts, false); left_sidebar_navigation_area.update_dom_with_unread_counts(counts, false);
left_sidebar_navigation_area.update_starred_count(444, true); left_sidebar_navigation_area.update_starred_count(444, true);
left_sidebar_navigation_area.update_scheduled_messages_row(); left_sidebar_navigation_area.update_scheduled_messages_row();
left_sidebar_navigation_area.update_reminders_row();
assert.ok(!$("<mentioned-count>").visible()); assert.ok(!$("<mentioned-count>").visible());
assert.equal($("<mentioned-count>").text(), ""); assert.equal($("<mentioned-count>").text(), "");
assert.equal($("<starred-count>").text(), "444"); assert.equal($("<starred-count>").text(), "444");
assert.ok(!$(".top_left_scheduled_messages").visible()); assert.ok(!$(".top_left_scheduled_messages").visible());
assert.ok(!$(".top_left_reminders").visible());
}); });

View File

@@ -655,6 +655,29 @@ exports.fixtures = {
value: false, value: false,
}, },
reminders__add: {
type: "reminders",
op: "add",
reminders: [
{
reminder_id: 17,
type: "private",
to: [6],
content: "Hello there!",
rendered_content: "<p>Hello there!</p>",
scheduled_delivery_timestamp: 1681662420,
failed: false,
reminder_target_message_id: 213,
},
],
},
reminders__remove: {
type: "reminders",
op: "remove",
reminder_id: 17,
},
restart: { restart: {
type: "restart", type: "restart",
zulip_version: "9.0-dev-753-gced3e85da9", zulip_version: "9.0-dev-753-gced3e85da9",