modal: Add options for marking messages as read.

We have updated our read messages confirmation modal
to now offer three options for marking messages as read:

- Muted topic messages
- Messages from topics I don't follow
- All unread messages

Additionally, the modal now displays the count of unread
messages for the selected option.

Fixes: #30025.
This commit is contained in:
whilstsomebody
2024-10-29 13:29:36 +05:30
committed by Tim Abbott
parent 01ce268d64
commit bbc842484f
9 changed files with 146 additions and 10 deletions

View File

@@ -46,7 +46,7 @@ function register_mark_all_read_handler(
>,
): void {
const {instance} = event.data;
unread_ops.confirm_mark_all_as_read();
unread_ops.confirm_mark_messages_as_read();
popover_menus.hide_current_popover_if_visible(instance);
}

View File

@@ -41,6 +41,10 @@ export function clear_old_unreads_missing(): void {
old_unreads_missing = false;
}
export function set_old_unreads_missing_for_tests(value: boolean): void {
old_unreads_missing = value;
}
export const unread_mentions_counter = new Set<number>();
export const direct_message_with_mention_count = new Set();
const unread_messages = new Set<number>();
@@ -912,6 +916,7 @@ export type FullUnreadCountsData = {
stream_unread_messages: number;
followed_topic_unread_messages_count: number;
followed_topic_unread_messages_with_mention_count: number;
unfollowed_topic_unread_messages_count: number;
muted_topic_unread_messages_count: number;
stream_count: Map<number, StreamCountInfo>;
streams_with_mentions: number[];
@@ -939,6 +944,8 @@ export function get_counts(): FullUnreadCountsData {
followed_topic_unread_messages_count: topic_res.followed_topic_unread_messages,
followed_topic_unread_messages_with_mention_count:
unread_topic_counter.get_followed_topic_unread_mentions(),
unfollowed_topic_unread_messages_count:
unread_messages.size - topic_res.followed_topic_unread_messages - pm_res.total_count,
muted_topic_unread_messages_count:
unread_messages.size - topic_res.stream_unread_messages - pm_res.total_count,
stream_count: topic_res.stream_count,

View File

@@ -3,7 +3,7 @@ import _ from "lodash";
import assert from "minimalistic-assert";
import {z} from "zod";
import render_confirm_mark_all_as_read from "../templates/confirm_dialog/confirm_mark_all_as_read.hbs";
import render_confirm_mark_messages_as_read from "../templates/confirm_dialog/confirm_mark_all_as_read.hbs";
import render_confirm_mark_as_unread_from_here from "../templates/confirm_dialog/confirm_mark_as_unread_from_here.hbs";
import render_inline_decorated_channel_name from "../templates/inline_decorated_channel_name.hbs";
import render_skipped_marking_unread from "../templates/skipped_marking_unread.hbs";
@@ -66,17 +66,37 @@ export function is_window_focused(): boolean {
return window_focused;
}
export function confirm_mark_all_as_read(): void {
const html_body = render_confirm_mark_all_as_read();
export function confirm_mark_messages_as_read(): void {
const html_body = render_confirm_mark_messages_as_read();
const modal_id = confirm_dialog.launch({
html_heading: $t_html({defaultMessage: "Mark all messages as read?"}),
html_heading: $t_html({defaultMessage: "Choose messages to mark as read"}),
html_body,
on_click() {
mark_all_as_read(modal_id);
handle_mark_messages_as_read(modal_id);
},
loading_spinner: true,
});
// When the user clicks on "Mark messages as read," the dialog box opens with a
// dropdown that, by default, displays the count of unread messages in
// topics that the user does not follow.
const default_messages_count = unread.get_counts().unfollowed_topic_unread_messages_count;
$("#message_count").text(get_message_count_text(default_messages_count));
// When the user selects another option from the dropdown, this section is executed.
$("#mark_as_read_option").on("change", function () {
const selected_option = $(this).val();
let messages_count;
if (selected_option === "muted_topics") {
messages_count = unread.get_counts().muted_topic_unread_messages_count;
} else if (selected_option === "topics_not_followed") {
messages_count = unread.get_counts().unfollowed_topic_unread_messages_count;
} else {
messages_count = unread.get_unread_message_count();
}
$("#message_count").text(get_message_count_text(messages_count));
});
}
const update_flags_for_narrow_response_schema = z.object({
@@ -129,6 +149,24 @@ function handle_skipped_unsubscribed_streams(
}
}
export function get_message_count_text(count: number): string {
if (unread.old_unreads_missing) {
return $t(
{
defaultMessage: "{count}+ messages will be marked as read.",
},
{count},
);
}
return $t(
{
defaultMessage:
"{count, plural, one {# message} other {# messages}} will be marked as read.",
},
{count},
);
}
function bulk_update_read_flags_for_narrow(
narrow: NarrowTerm[],
op: "add" | "remove",
@@ -329,6 +367,28 @@ function bulk_update_read_flags_for_narrow(
});
}
function handle_mark_messages_as_read(modal_id: string): void {
const selected_option = $("#mark_as_read_option").val();
switch (selected_option) {
case "muted_topics": {
mark_muted_topic_messages_as_read(modal_id);
break;
}
case "topics_not_followed": {
mark_unfollowed_topic_messages_as_read(modal_id);
break;
}
case "all_messages": {
mark_all_as_read(modal_id);
break;
}
default: {
assert(false, `Invalid mark_as_read_option: ${String(selected_option)}`);
}
}
}
function process_newly_read_message(
message: Message,
options: {from?: "pointer" | "server"},
@@ -838,6 +898,31 @@ export function mark_all_as_read(modal_id?: string): void {
bulk_update_read_flags_for_narrow(all_unread_messages_narrow, "add", {}, modal_id);
}
export function mark_muted_topic_messages_as_read(modal_id?: string): void {
bulk_update_read_flags_for_narrow(
[
{operator: "is", operand: "unread", negated: false},
{operator: "is", operand: "muted", negated: false},
],
"add",
{},
modal_id,
);
}
export function mark_unfollowed_topic_messages_as_read(modal_id?: string): void {
bulk_update_read_flags_for_narrow(
[
{operator: "is", operand: "unread", negated: false},
{operator: "is", operand: "followed", negated: true},
{operator: "is", operand: "dm", negated: true},
],
"add",
{},
modal_id,
);
}
export function mark_pm_as_read(user_ids_string: string): void {
// user_ids_string is a stringified list of user ids which are
// participants in the conversation other than the current

View File

@@ -367,6 +367,10 @@ select.settings_select {
& label.checkbox + label {
cursor: pointer;
}
.message_count {
margin: 10px 0 0;
}
}
/* Class for displaying an input with an

View File

@@ -1,3 +1,11 @@
<p>
{{t "Are you sure you want to mark all messages as read? This action cannot be undone." }}
{{t "Which messages do you want to mark as read? This action cannot be undone." }}
</p>
<div class="input-group">
<select id="mark_as_read_option" class="modal_select bootstrap-style-font">
<option value="muted_topics">{{t "Muted topics" }}</option>
<option value="topics_not_followed" selected>{{t "Topics you don't follow" }}</option>
<option value="all_messages">{{t "All messages" }}</option>
</select>
<p id="message_count" class="message_count"></p>
</div>

View File

@@ -5,7 +5,7 @@
<li role="none" class="link-item popover-menu-list-item">
<a role="menuitem" id="mark_all_messages_as_read" class="popover-menu-link" tabindex="0">
<i class="popover-menu-icon zulip-icon zulip-icon-mark-as-read" aria-hidden="true"></i>
<span class="popover-menu-label">{{t "Mark all messages as read" }}</span>
<span class="popover-menu-label">{{t "Mark messages as read" }}</span>
</a>
</li>
{{/if}}

View File

@@ -5,7 +5,7 @@
<li role="none" class="link-item popover-menu-list-item">
<a role="menuitem" id="mark_all_messages_as_read" class="popover-menu-link" tabindex="0">
<i class="popover-menu-icon zulip-icon zulip-icon-mark-as-read" aria-hidden="true"></i>
<span class="popover-menu-label">{{t "Mark all messages as read" }}</span>
<span class="popover-menu-label">{{t "Mark messages as read" }}</span>
</a>
</li>
{{/if}}

View File

@@ -5,7 +5,7 @@
<li role="none" class="link-item popover-menu-list-item">
<a role="menuitem" id="mark_all_messages_as_read" class="popover-menu-link" tabindex="0">
<i class="popover-menu-icon zulip-icon zulip-icon-mark-as-read" aria-hidden="true"></i>
<span class="popover-menu-label">{{t "Mark all messages as read" }}</span>
<span class="popover-menu-label">{{t "Mark messages as read" }}</span>
</a>
</li>
{{/if}}

View File

@@ -0,0 +1,32 @@
"use strict";
const assert = require("node:assert/strict");
const {set_global, zrequire} = require("./lib/namespace.cjs");
const {run_test} = require("./lib/test.cjs");
set_global("document", {hasFocus: () => true});
const unread = zrequire("unread");
const unread_ops = zrequire("unread_ops");
run_test("get_message_count_text", () => {
unread.set_old_unreads_missing_for_tests(true);
assert.equal(
unread_ops.get_message_count_text(5),
"translated: 5+ messages will be marked as read.",
);
assert.equal(
unread_ops.get_message_count_text(1),
"translated: 1+ messages will be marked as read.",
);
unread.set_old_unreads_missing_for_tests(false);
assert.equal(
unread_ops.get_message_count_text(5),
"translated: 5 messages will be marked as read.",
);
assert.equal(
unread_ops.get_message_count_text(1),
"translated: 1 message will be marked as read.",
);
});