compose: Show counter inside Drafts button for the current recipient.

Now we show the number of drafts that are addressed to the current
recipient selected in the compose box, if any, in the Drafts button
within parentheses (whether it is next to the Send button, or in the
Send options popover), and explain that it is the number of drafts for
this conversation in the tooltip.

Fixes: #28696.
This commit is contained in:
N-Shar-ma 2024-02-07 12:44:58 +05:30 committed by Tim Abbott
parent 6ec04c2469
commit f4d58f1ba6
13 changed files with 78 additions and 19 deletions

View File

@ -308,6 +308,7 @@ export function start(msg_type, opts) {
}
compose_recipient.check_posting_policy_for_compose_box();
drafts.update_compose_draft_count();
// Reset the `max-height` property of `compose-textarea` so that the
// compose-box do not cover the last messages of the current stream
@ -410,6 +411,7 @@ export function on_topic_narrow() {
compose_validate.warn_if_topic_resolved(true);
compose_fade.set_focused_recipient("stream");
compose_fade.update_message_list();
drafts.update_compose_draft_count();
$("textarea#compose-textarea").trigger("focus");
}

View File

@ -11,6 +11,7 @@ import * as compose_pm_pill from "./compose_pm_pill";
import * as compose_state from "./compose_state";
import * as compose_ui from "./compose_ui";
import * as compose_validate from "./compose_validate";
import * as drafts from "./drafts";
import * as dropdown_widget from "./dropdown_widget";
import {$t} from "./i18n";
import * as narrow_state from "./narrow_state";
@ -95,6 +96,7 @@ function update_fade() {
export function update_on_recipient_change() {
update_fade();
update_narrow_to_recipient_visibility();
drafts.update_compose_draft_count();
check_posting_policy_for_compose_box();
}

View File

@ -2,6 +2,7 @@ import $ from "jquery";
import _ from "lodash";
import {delegate} from "tippy.js";
import render_drafts_tooltip from "../templates/drafts_tooltip.hbs";
import render_narrow_to_compose_recipients_tooltip from "../templates/narrow_to_compose_recipients_tooltip.hbs";
import * as compose_recipient from "./compose_recipient";
@ -104,11 +105,24 @@ export function initialize() {
target: ".send-control-button",
delay: LONG_HOVER_DELAY,
placement: "top",
onShow() {
onShow(instance) {
// Don't show send-area tooltips if the popover is displayed.
if (popover_menus.is_scheduled_messages_popover_displayed()) {
return false;
}
if (instance.reference.id === "compose-drafts-button") {
const count =
instance.reference.querySelector(".compose-drafts-count").textContent || 0;
// Explain that the number in brackets is the number of drafts for this conversation.
const draft_count_msg = $t(
{
defaultMessage:
"{count, plural, one {# draft} other {# drafts}} for this conversation",
},
{count},
);
instance.setContent(parse_html(render_drafts_tooltip({draft_count_msg})));
}
return true;
},
appendTo: () => document.body,

View File

@ -157,6 +157,7 @@ export const draft_model = (function () {
ls.set(KEY, drafts);
if (update_count) {
set_count(Object.keys(drafts).length);
update_compose_draft_count();
}
}
@ -208,6 +209,24 @@ export const draft_model = (function () {
};
})();
export function update_compose_draft_count(): void {
const $count_container = $(".compose-drafts-count-container");
const $count_ele = $count_container.find(".compose-drafts-count");
if (!compose_state.has_full_recipient()) {
$count_ele.text("");
$count_container.hide();
return;
}
const compose_draft_count = Object.keys(filter_drafts_by_compose_box_and_recipient()).length;
if (compose_draft_count > 0) {
$count_ele.text(compose_draft_count > 99 ? "99+" : compose_draft_count);
$count_container.show();
} else {
$count_ele.text("");
$count_container.hide();
}
}
export function sync_count(): void {
const drafts = draft_model.get();
set_count(Object.keys(drafts).length);

View File

@ -10,6 +10,7 @@ import * as channel from "./channel";
import * as common from "./common";
import * as compose from "./compose";
import * as compose_validate from "./compose_validate";
import * as drafts from "./drafts";
import * as flatpickr from "./flatpickr";
import * as modals from "./modals";
import * as popover_menus from "./popover_menus";
@ -165,6 +166,8 @@ export function initialize() {
focus_first_send_later_popover_item();
send_later_popover_keyboard_toggle = false;
}
// Make sure the compose drafts count, which is also displayed in this popover, has a current value.
drafts.update_compose_draft_count();
const $popper = $(instance.popper);
common.adjust_mac_kbd_tags(".enter_sends_choices kbd");
$popper.one("click", ".send_later_selected_send_later_time", () => {

View File

@ -1334,12 +1334,18 @@ textarea.new_message_textarea,
as 100% of the container width, plus
the 8px from the negative left margin. */
max-width: calc(100% + 8px);
display: flex;
gap: 1px;
.compose-drafts-text {
/* Set an ellipsis when the translated
version of `Drafts` exceeds the width,
and keep button text to a single line. */
white-space: nowrap;
overflow-x: hidden;
text-overflow: ellipsis;
flex-grow: 1;
}
@media (width < $mc_min) {
margin-left: 0;

View File

@ -86,8 +86,8 @@
<div class="drag"></div>
<div id="message-send-controls-container">
<a id="compose-drafts-button" role="button" class="send-control-button hide-sm" tabindex=0 href="#drafts" data-tooltip-template-id="compose_draft_tooltip_template">
{{t 'Drafts' }}
<a id="compose-drafts-button" role="button" class="send-control-button hide-sm" tabindex=0 href="#drafts">
<span class="compose-drafts-text">{{t 'Drafts' }}</span><span class="compose-drafts-count-container">(<span class="compose-drafts-count"></span>)</span>
</a>
<span id="compose-limit-indicator"></span>
<div class="message-send-controls">

View File

@ -0,0 +1,7 @@
<div>
<div>{{t "View drafts"}}</div>
{{#if draft_count_msg}}
<div class="tooltip-inner-content italic">{{draft_count_msg}}</div>
{{/if}}
</div>
{{tooltip_hotkey_hints "D"}}

View File

@ -51,6 +51,6 @@
</li>
<hr class="drafts-item-in-popover" />
<li class="drafts-item-in-popover">
<a href="#drafts">{{t "Drafts"}}</a>
<a href="#drafts">{{t "Drafts"}} <span class="compose-drafts-count-container">(<span class="compose-drafts-count"></span>)</span></a>
</li>
</ul>

View File

@ -6,10 +6,6 @@
{{t 'View bot card' }}
{{tooltip_hotkey_hints "U"}}
</template>
<template id="compose_draft_tooltip_template">
{{t 'Drafts' }}
{{tooltip_hotkey_hints "D"}}
</template>
<template id="scroll-to-bottom-button-tooltip-template">
{{t 'Scroll to bottom' }}
{{tooltip_hotkey_hints "End"}}

View File

@ -234,6 +234,7 @@ test_ui("send_message", ({override, override_rewire, mock_template}) => {
const $container = $(".top_left_drafts");
const $child = $(".unread_count");
$container.set_find_results(".unread_count", $child);
override_rewire(drafts, "update_compose_draft_count", noop);
override(server_events, "assert_get_events_running", () => {
stub_state.get_events_running_called += 1;
@ -576,6 +577,7 @@ test_ui("update_fade", ({override, override_rewire}) => {
override_rewire(compose_recipient, "update_narrow_to_recipient_visibility", () => {
update_narrow_to_recipient_visibility_called = true;
});
override_rewire(drafts, "update_compose_draft_count", noop);
compose_state.set_message_type(undefined);
compose_recipient.update_on_recipient_change();

View File

@ -45,6 +45,7 @@ mock_esm("../src/reload_state", {
});
mock_esm("../src/drafts", {
update_draft: noop,
update_compose_draft_count: noop,
});
mock_esm("../src/unread_ops", {
notify_server_message_read: noop,

View File

@ -144,25 +144,27 @@ test("fix buggy drafts", ({override_rewire}) => {
assert.equal(draft.topic, "");
});
test("draft_model add", () => {
test("draft_model add", ({override_rewire}) => {
const draft_model = drafts.draft_model;
const ls = localstorage();
assert.equal(ls.get("draft"), undefined);
const $unread_count = $("<unread-count-stub>");
$(".top_left_drafts").set_find_results(".unread_count", $unread_count);
override_rewire(drafts, "update_compose_draft_count", noop);
const id = draft_model.addDraft(draft_1);
assert.deepEqual(draft_model.getDraft(id), draft_1);
});
test("draft_model edit", () => {
test("draft_model edit", ({override_rewire}) => {
const draft_model = drafts.draft_model;
const ls = localstorage();
assert.equal(ls.get("draft"), undefined);
const $unread_count = $("<unread-count-stub>");
$(".top_left_drafts").set_find_results(".unread_count", $unread_count);
override_rewire(drafts, "update_compose_draft_count", noop);
const id = draft_model.addDraft(draft_1);
assert.deepEqual(draft_model.getDraft(id), draft_1);
@ -171,13 +173,14 @@ test("draft_model edit", () => {
assert.deepEqual(draft_model.getDraft(id), draft_2);
});
test("draft_model delete", () => {
test("draft_model delete", ({override_rewire}) => {
const draft_model = drafts.draft_model;
const ls = localstorage();
assert.equal(ls.get("draft"), undefined);
const $unread_count = $("<unread-count-stub>");
$(".top_left_drafts").set_find_results(".unread_count", $unread_count);
override_rewire(drafts, "update_compose_draft_count", noop);
const id = draft_model.addDraft(draft_1);
assert.deepEqual(draft_model.getDraft(id), draft_1);
@ -253,7 +256,7 @@ test("initialize", ({override_rewire}) => {
drafts_overlay_ui.initialize();
});
test("remove_old_drafts", () => {
test("remove_old_drafts", ({override_rewire}) => {
const draft_3 = {
topic: "topic",
type: "stream",
@ -275,6 +278,7 @@ test("remove_old_drafts", () => {
const $unread_count = $("<unread-count-stub>");
$(".top_left_drafts").set_find_results(".unread_count", $unread_count);
override_rewire(drafts, "update_compose_draft_count", noop);
drafts.remove_old_drafts();
assert.deepEqual(draft_model.get(), {id3: draft_3});
@ -294,6 +298,7 @@ test("update_draft", ({override, override_rewire}) => {
const $container = $(".top_left_drafts");
const $child = $(".unread_count");
$container.set_find_results(".unread_count", $child);
override_rewire(drafts, "update_compose_draft_count", noop);
tippy_args = {
content: "translated: Saved as draft",
@ -343,6 +348,7 @@ test("update_draft", ({override, override_rewire}) => {
test("rename_stream_recipient", ({override_rewire}) => {
override_rewire(drafts, "set_count", noop);
override_rewire(drafts, "update_compose_draft_count", noop);
const stream_A = {
subscribed: false,
@ -425,7 +431,7 @@ test("rename_stream_recipient", ({override_rewire}) => {
assert_draft("id4", stream_B.stream_id, "e");
});
test("delete_all_drafts", () => {
test("delete_all_drafts", ({override_rewire}) => {
const draft_model = drafts.draft_model;
const ls = localstorage();
const data = {draft_1, draft_2, short_msg};
@ -434,6 +440,7 @@ test("delete_all_drafts", () => {
const $unread_count = $("<unread-count-stub>");
$(".top_left_drafts").set_find_results(".unread_count", $unread_count);
override_rewire(drafts, "update_compose_draft_count", noop);
drafts.delete_all_drafts();
assert.deepEqual(draft_model.get(), {});