compose: Handle fading with general chat.

This commit also attempts to fix a bug, present in main, where a
draft restored directly to the compose box loses its original topic
upon switching to other topic narrows.

Co-authored-by: Prakhar Pratyush <prakhar@zulip.com>
This commit is contained in:
Karl Stolley
2025-02-11 14:03:33 -05:00
committed by Tim Abbott
parent 4723492e12
commit a3a43c2f8b
10 changed files with 74 additions and 13 deletions

View File

@@ -26,6 +26,7 @@ import * as reload_state from "./reload_state.ts";
import * as resize from "./resize.ts";
import * as saved_snippets_ui from "./saved_snippets_ui.ts";
import * as spectators from "./spectators.ts";
import {realm} from "./state_data.ts";
import * as stream_data from "./stream_data.ts";
// Opts sent to `compose_actions.start`.
@@ -516,7 +517,8 @@ export let on_topic_narrow = (): void => {
}
if (
(compose_state.topic() && compose_state.has_novel_message_content()) ||
((compose_state.topic() || !realm.realm_mandatory_topics) &&
compose_state.has_message_content()) ||
compose_state.is_recipient_edited_manually()
) {
// If the user has written something to a different topic or edited it,

View File

@@ -105,7 +105,7 @@ function fade_messages(): void {
);
}
function do_update_all(): void {
export function do_update_all(): void {
if (compose_fade_helper.want_normal_display()) {
if (!normal_display) {
display_messages_normally();

View File

@@ -1,4 +1,7 @@
import $ from "jquery";
import type {Message} from "./message_store.ts";
import {realm} from "./state_data.ts";
import * as sub_store from "./sub_store.ts";
import type {Recipient} from "./util.ts";
import * as util from "./util.ts";
@@ -31,11 +34,14 @@ export function want_normal_display(): boolean {
return true;
}
// This is kind of debatable. If the topic is empty, it could be that
// the user simply hasn't started typing it yet, but disabling fading here
// means the feature doesn't help realms where topics aren't mandatory
// (which is most realms as of this writing).
if (focused_recipient.topic === "") {
// If the topic is empty, we want a normal display in the following cases:
// * realm requires topic
// * realm allows empty topic but the focus is in topic input box,
// means user is still configuring topic.
if (
focused_recipient.topic === "" &&
(realm.realm_mandatory_topics || $("input#stream_message_recipient_topic").is(":focus"))
) {
return true;
}
}

View File

@@ -10,6 +10,7 @@ import * as compose_actions from "./compose_actions.ts";
import * as compose_banner from "./compose_banner.ts";
import * as compose_call from "./compose_call.ts";
import * as compose_call_ui from "./compose_call_ui.ts";
import * as compose_fade from "./compose_fade.ts";
import * as compose_notifications from "./compose_notifications.ts";
import * as compose_recipient from "./compose_recipient.ts";
import * as compose_send_menu_popover from "./compose_send_menu_popover.js";
@@ -583,6 +584,7 @@ export function initialize() {
$("textarea#compose-textarea").on("focus", () => {
compose_recipient.update_compose_area_placeholder_text();
compose_fade.do_update_all();
if (narrow_state.narrowed_by_reply()) {
compose_notifications.maybe_show_one_time_non_interleaved_view_messages_fading_banner();
} else {

View File

@@ -2,6 +2,7 @@ import $ from "jquery";
import * as compose_pm_pill from "./compose_pm_pill.ts";
import * as people from "./people.ts";
import {realm} from "./state_data.ts";
import * as sub_store from "./sub_store.ts";
let message_type: "stream" | "private" | undefined;
@@ -231,7 +232,8 @@ export function has_savable_message_content(): boolean {
export function has_full_recipient(): boolean {
if (message_type === "stream") {
return stream_id() !== undefined && topic() !== "";
const has_topic = topic() !== "" || !realm.realm_mandatory_topics;
return stream_id() !== undefined && has_topic;
}
return private_message_recipient() !== "";
}

View File

@@ -1378,7 +1378,7 @@ export function to_compose_target(): void {
// grey-out the message view instead of narrowing to an empty view.
const terms = [{operator: "channel", operand: stream_id.toString()}];
const topic = compose_state.topic();
if (topic !== "") {
if (topic !== "" || !realm.realm_mandatory_topics) {
terms.push({operator: "topic", operand: topic});
}
show(terms, opts);

View File

@@ -823,6 +823,7 @@ test_ui("on_events", ({override, override_rewire}) => {
fake_compose_box.show_message_preview();
override_rewire(compose_recipient, "update_compose_area_placeholder_text", noop);
override(compose_fade, "do_update_all", noop);
override(narrow_state, "narrowed_by_reply", () => true);
override(
compose_notifications,

View File

@@ -12,6 +12,15 @@ mock_jquery((selector) => {
val() {
return "lunch";
},
is(arg) {
switch (arg) {
case ":focus":
return true;
/* istanbul ignore next */
default:
throw new Error(`Unknown arg ${arg}`);
}
},
};
/* istanbul ignore next */
default:
@@ -25,6 +34,10 @@ const people = zrequire("people");
const compose_fade = zrequire("compose_fade");
const compose_fade_helper = zrequire("compose_fade_helper");
const compose_state = zrequire("compose_state");
const {set_realm} = zrequire("state_data");
const realm = {};
set_realm(realm);
const me = {
email: "me@example.com",
@@ -77,7 +90,7 @@ run_test("set_focused_recipient", () => {
assert.ok(compose_fade_helper.should_fade_message(bad_msg));
});
run_test("want_normal_display", () => {
run_test("want_normal_display", ({override}) => {
const stream_id = 110;
const sub = {
stream_id,
@@ -100,9 +113,16 @@ run_test("want_normal_display", () => {
assert.ok(compose_fade_helper.want_normal_display());
// Focused recipient is a valid stream with no topic set
// when topics are mandatory
override(realm, "realm_mandatory_topics", true);
stream_data.add_sub(sub);
assert.ok(compose_fade_helper.want_normal_display());
// Focused recipient is a valid stream with no topic set
// when topics are not mandatory. Focused to input box.
override(realm, "realm_mandatory_topics", false);
assert.ok(compose_fade_helper.want_normal_display());
// If we're focused to a topic, then we do want to fade.
compose_fade_helper.set_focused_recipient({
type: "stream",

View File

@@ -10,6 +10,10 @@ const compose_pm_pill = mock_esm("../src/compose_pm_pill");
const compose_state = zrequire("compose_state");
const stream_data = zrequire("stream_data");
const {set_realm} = zrequire("state_data");
const realm = {};
set_realm(realm);
run_test("private_message_recipient", ({override}) => {
let emails;

View File

@@ -769,7 +769,7 @@ run_test("narrow_to_compose_target errors", ({disallow_rewire}) => {
message_view.to_compose_target();
});
run_test("narrow_to_compose_target streams", ({override_rewire}) => {
run_test("narrow_to_compose_target streams", ({override, override_rewire}) => {
const args = {called: false};
override_rewire(message_view, "show", (terms, opts) => {
args.terms = terms;
@@ -803,19 +803,43 @@ run_test("narrow_to_compose_target streams", ({override_rewire}) => {
{operator: "topic", operand: "four"},
]);
// Test with blank topic
// Test with blank topic, with realm_mandatory_topics
override(realm, "realm_mandatory_topics", true);
compose_state.topic("");
args.called = false;
message_view.to_compose_target();
assert.equal(args.called, true);
assert.deepEqual(args.terms, [{operator: "channel", operand: rome_id.toString()}]);
// Test with no topic
// Test with blank topic, without realm_mandatory_topics
override(realm, "realm_mandatory_topics", false);
compose_state.topic("");
args.called = false;
message_view.to_compose_target();
assert.equal(args.called, true);
assert.deepEqual(args.terms, [
{operator: "channel", operand: rome_id.toString()},
{operator: "topic", operand: ""},
]);
// Test with no topic, with realm mandatory topics
override(realm, "realm_mandatory_topics", true);
compose_state.topic(undefined);
args.called = false;
message_view.to_compose_target();
assert.equal(args.called, true);
assert.deepEqual(args.terms, [{operator: "channel", operand: rome_id.toString()}]);
// Test with no topic, without realm mandatory topics
override(realm, "realm_mandatory_topics", false);
compose_state.topic(undefined);
args.called = false;
message_view.to_compose_target();
assert.equal(args.called, true);
assert.deepEqual(args.terms, [
{operator: "channel", operand: rome_id.toString()},
{operator: "topic", operand: ""},
]);
});
run_test("narrow_to_compose_target direct messages", ({override, override_rewire}) => {