mirror of
https://github.com/zulip/zulip.git
synced 2025-11-11 09:27:43 +00:00
compose: Migrate generic error to use shared banner template.
Error banners were rendered in a different place than warnings. Now compose errors and warnings share the same template and styling in compose_banner.hbs Testing notes: * I removed test_message_overflow since it seemed not to test anything that test_check_overflow_text wasn't already testing. * private_message_recipient() can't be called to set emails to non-valid emails, so `invalid_recipient` cannot be tested (and is likely very difficult to trigger in production, if possible at all).
This commit is contained in:
@@ -4,7 +4,7 @@ const {strict: assert} = require("assert");
|
||||
|
||||
const MockDate = require("mockdate");
|
||||
|
||||
const {$t, $t_html} = require("../zjsunit/i18n");
|
||||
const {$t} = require("../zjsunit/i18n");
|
||||
const {mock_esm, set_global, zrequire} = require("../zjsunit/namespace");
|
||||
const {run_test} = require("../zjsunit/test");
|
||||
const blueslip = require("../zjsunit/zblueslip");
|
||||
@@ -135,7 +135,7 @@ test_ui("send_message_success", ({override_rewire}) => {
|
||||
assert.ok(reify_message_id_checked);
|
||||
});
|
||||
|
||||
test_ui("send_message", ({override, override_rewire}) => {
|
||||
test_ui("send_message", ({override, override_rewire, mock_template}) => {
|
||||
mock_banners();
|
||||
MockDate.set(new Date(fake_now * 1000));
|
||||
|
||||
@@ -258,6 +258,12 @@ test_ui("send_message", ({override, override_rewire}) => {
|
||||
})();
|
||||
|
||||
(function test_error_codepath_local_id_undefined() {
|
||||
let banner_rendered = false;
|
||||
mock_template("compose_banner/compose_banner.hbs", false, (data) => {
|
||||
assert.equal(data.classname, "generic_compose_error");
|
||||
assert.equal(data.banner_text, "Error sending message: Server says 408");
|
||||
banner_rendered = true;
|
||||
});
|
||||
stub_state = initialize_state_stub_dict();
|
||||
$("#compose-textarea").val("foobarfoobar");
|
||||
$("#compose-textarea").trigger("blur");
|
||||
@@ -278,7 +284,7 @@ test_ui("send_message", ({override, override_rewire}) => {
|
||||
};
|
||||
assert.deepEqual(stub_state, state);
|
||||
assert.ok(!echo_error_msg_checked);
|
||||
assert.equal($("#compose-error-msg").html(), "Error sending message: Server says 408");
|
||||
assert.ok(banner_rendered);
|
||||
assert.equal($("#compose-textarea").val(), "foobarfoobar");
|
||||
assert.ok($("#compose-textarea").is_focused());
|
||||
assert.ok($("#compose-send-status").visible());
|
||||
@@ -335,7 +341,7 @@ test_ui("enter_with_preview_open", ({override, override_rewire}) => {
|
||||
assert.equal($("#compose-error-msg").html(), "never-been-set");
|
||||
});
|
||||
|
||||
test_ui("finish", ({override, override_rewire}) => {
|
||||
test_ui("finish", ({override, override_rewire, mock_template}) => {
|
||||
mock_banners();
|
||||
override(notifications, "clear_compose_notifications", () => {});
|
||||
override(reminder, "is_deferred_delivery", () => false);
|
||||
@@ -347,6 +353,10 @@ test_ui("finish", ({override, override_rewire}) => {
|
||||
});
|
||||
|
||||
(function test_when_compose_validation_fails() {
|
||||
mock_template("compose_banner/compose_banner.hbs", false, (data) => {
|
||||
assert.equal(data.classname, "empty_message");
|
||||
assert.equal(data.banner_text, $t({defaultMessage: "You have nothing to send!"}));
|
||||
});
|
||||
$("#compose_invite_users").show();
|
||||
$("#compose-send-button").prop("disabled", false);
|
||||
$("#compose-send-button").trigger("focus");
|
||||
@@ -357,10 +367,6 @@ test_ui("finish", ({override, override_rewire}) => {
|
||||
assert.equal(res, false);
|
||||
assert.ok(!$("#compose_invite_users").visible());
|
||||
assert.ok(!$("#compose-send-button .loader").visible());
|
||||
assert.equal(
|
||||
$("#compose-error-msg").html(),
|
||||
$t_html({defaultMessage: "You have nothing to send!"}),
|
||||
);
|
||||
assert.ok(show_button_spinner_called);
|
||||
})();
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
const {strict: assert} = require("assert");
|
||||
|
||||
const {$t, $t_html} = require("../zjsunit/i18n");
|
||||
const {$t} = require("../zjsunit/i18n");
|
||||
const {mock_esm, zrequire} = require("../zjsunit/namespace");
|
||||
const {run_test} = require("../zjsunit/test");
|
||||
const blueslip = require("../zjsunit/zblueslip");
|
||||
@@ -13,7 +13,6 @@ const {mock_banners} = require("./lib/compose_banner");
|
||||
|
||||
const channel = mock_esm("../../static/js/channel");
|
||||
const compose_actions = mock_esm("../../static/js/compose_actions");
|
||||
const ui_util = mock_esm("../../static/js/ui_util");
|
||||
|
||||
const compose_error = zrequire("compose_error");
|
||||
const compose_pm_pill = zrequire("compose_pm_pill");
|
||||
@@ -70,6 +69,7 @@ function test_ui(label, f) {
|
||||
}
|
||||
|
||||
test_ui("validate_stream_message_address_info", ({mock_template}) => {
|
||||
mock_banners();
|
||||
const sub = {
|
||||
stream_id: 101,
|
||||
name: "social",
|
||||
@@ -103,25 +103,31 @@ test_ui("validate_stream_message_address_info", ({mock_template}) => {
|
||||
assert.ok(!compose_validate.validate_stream_message_address_info("Frontend"));
|
||||
assert.equal($("#compose-error-msg").html(), "compose_not_subscribed_stub");
|
||||
|
||||
let stream_does_not_exist_rendered = false;
|
||||
mock_template("compose_banner/stream_does_not_exist_error.hbs", false, (data) => {
|
||||
assert.equal(data.classname, compose_error.CLASSNAMES.stream_does_not_exist);
|
||||
assert.equal(data.stream_name, "Frontend");
|
||||
stream_does_not_exist_rendered = true;
|
||||
});
|
||||
channel.post = (payload) => {
|
||||
assert.equal(payload.data.stream, "Frontend");
|
||||
payload.error({status: 404});
|
||||
};
|
||||
assert.ok(!compose_validate.validate_stream_message_address_info("Frontend"));
|
||||
assert.equal(
|
||||
$("#compose-error-msg").html(),
|
||||
"translated HTML: <p>The stream <b>Frontend</b> does not exist.</p><p>Manage your subscriptions <a href='#streams/all'>on your Streams page</a>.</p>",
|
||||
);
|
||||
assert.ok(stream_does_not_exist_rendered);
|
||||
|
||||
let subscription_error_rendered = false;
|
||||
mock_template("compose_banner/compose_banner.hbs", false, (data) => {
|
||||
assert.equal(data.classname, "subscription_error");
|
||||
assert.equal(data.banner_text, $t({defaultMessage: "Error checking subscription."}));
|
||||
subscription_error_rendered = true;
|
||||
});
|
||||
channel.post = (payload) => {
|
||||
assert.equal(payload.data.stream, "social");
|
||||
payload.error({status: 500});
|
||||
};
|
||||
assert.ok(!compose_validate.validate_stream_message_address_info("social"));
|
||||
assert.equal(
|
||||
$("#compose-error-msg").html(),
|
||||
$t_html({defaultMessage: "Error checking subscription"}),
|
||||
);
|
||||
assert.ok(subscription_error_rendered);
|
||||
});
|
||||
|
||||
test_ui("validate", ({override, mock_template}) => {
|
||||
@@ -142,26 +148,87 @@ test_ui("validate", ({override, mock_template}) => {
|
||||
|
||||
compose_pm_pill.initialize();
|
||||
|
||||
ui_util.place_caret_at_end = () => {};
|
||||
|
||||
$("#zephyr-mirror-error").is = () => {};
|
||||
|
||||
mock_template("input_pill.hbs", false, () => "<div>pill-html</div>");
|
||||
|
||||
mock_banners();
|
||||
}
|
||||
|
||||
function add_content_to_compose_box() {
|
||||
$("#compose-textarea").val("foobarfoobar");
|
||||
}
|
||||
|
||||
// test validating private messages
|
||||
compose_state.set_message_type("private");
|
||||
|
||||
initialize_pm_pill();
|
||||
add_content_to_compose_box();
|
||||
compose_state.private_message_recipient("");
|
||||
let pm_recipient_error_rendered = false;
|
||||
mock_template("compose_banner/compose_banner.hbs", false, (data) => {
|
||||
assert.equal(data.classname, compose_error.CLASSNAMES.missing_private_message_recipient);
|
||||
assert.equal(
|
||||
data.banner_text,
|
||||
$t({defaultMessage: "Please specify at least one valid recipient."}),
|
||||
);
|
||||
pm_recipient_error_rendered = true;
|
||||
});
|
||||
assert.ok(!compose_validate.validate());
|
||||
assert.ok(pm_recipient_error_rendered);
|
||||
|
||||
pm_recipient_error_rendered = false;
|
||||
|
||||
people.add_active_user(bob);
|
||||
compose_state.private_message_recipient("bob@example.com");
|
||||
assert.ok(compose_validate.validate());
|
||||
assert.ok(!pm_recipient_error_rendered);
|
||||
|
||||
people.deactivate(bob);
|
||||
let deactivated_user_error_rendered = false;
|
||||
mock_template("compose_banner/compose_banner.hbs", false, (data) => {
|
||||
assert.equal(data.classname, compose_error.CLASSNAMES.deactivated_user);
|
||||
assert.equal(
|
||||
data.banner_text,
|
||||
$t({defaultMessage: "You cannot send messages to deactivated users."}),
|
||||
);
|
||||
deactivated_user_error_rendered = true;
|
||||
});
|
||||
assert.ok(!compose_validate.validate());
|
||||
assert.ok(deactivated_user_error_rendered);
|
||||
|
||||
page_params.realm_is_zephyr_mirror_realm = true;
|
||||
assert.ok(compose_validate.validate());
|
||||
page_params.realm_is_zephyr_mirror_realm = false;
|
||||
|
||||
initialize_pm_pill();
|
||||
add_content_to_compose_box();
|
||||
compose_state.private_message_recipient("welcome-bot@example.com");
|
||||
assert.ok(compose_validate.validate());
|
||||
|
||||
let zephyr_error_rendered = false;
|
||||
let empty_message_error_rendered = false;
|
||||
mock_template("compose_banner/compose_banner.hbs", false, (data) => {
|
||||
if (data.classname === compose_error.CLASSNAMES.zephyr_not_running) {
|
||||
assert.equal(
|
||||
data.banner_text,
|
||||
$t({
|
||||
defaultMessage:
|
||||
"You need to be running Zephyr mirroring in order to send messages!",
|
||||
}),
|
||||
);
|
||||
zephyr_error_rendered = true;
|
||||
} else if (data.classname === compose_error.CLASSNAMES.empty_message) {
|
||||
assert.equal(data.banner_text, $t({defaultMessage: "You have nothing to send!"}));
|
||||
empty_message_error_rendered = true;
|
||||
}
|
||||
});
|
||||
initialize_pm_pill();
|
||||
compose_state.private_message_recipient("welcome-bot@example.com");
|
||||
assert.ok(!compose_validate.validate());
|
||||
assert.ok(!$("#compose-send-button .loader").visible());
|
||||
assert.equal($("#compose-send-button").prop("disabled"), false);
|
||||
assert.equal(
|
||||
$("#compose-error-msg").html(),
|
||||
$t_html({defaultMessage: "You have nothing to send!"}),
|
||||
);
|
||||
|
||||
assert.ok(empty_message_error_rendered);
|
||||
compose_validate.validate();
|
||||
|
||||
add_content_to_compose_box();
|
||||
@@ -173,88 +240,42 @@ test_ui("validate", ({override, mock_template}) => {
|
||||
};
|
||||
assert.ok(!compose_validate.validate());
|
||||
assert.ok(zephyr_checked);
|
||||
assert.equal(
|
||||
$("#compose-error-msg").html(),
|
||||
$t_html({
|
||||
defaultMessage: "You need to be running Zephyr mirroring in order to send messages!",
|
||||
}),
|
||||
);
|
||||
assert.ok(zephyr_error_rendered);
|
||||
|
||||
initialize_pm_pill();
|
||||
add_content_to_compose_box();
|
||||
|
||||
// test validating private messages
|
||||
compose_state.set_message_type("private");
|
||||
|
||||
compose_state.private_message_recipient("");
|
||||
assert.ok(!compose_validate.validate());
|
||||
assert.equal(
|
||||
$("#compose-error-msg").html(),
|
||||
$t_html({defaultMessage: "Please specify at least one valid recipient"}),
|
||||
);
|
||||
|
||||
initialize_pm_pill();
|
||||
add_content_to_compose_box();
|
||||
compose_state.private_message_recipient("foo@zulip.com");
|
||||
|
||||
assert.ok(!compose_validate.validate());
|
||||
|
||||
assert.equal(
|
||||
$("#compose-error-msg").html(),
|
||||
$t_html({defaultMessage: "Please specify at least one valid recipient"}),
|
||||
);
|
||||
|
||||
compose_state.private_message_recipient("foo@zulip.com,alice@zulip.com");
|
||||
assert.ok(!compose_validate.validate());
|
||||
|
||||
assert.equal(
|
||||
$("#compose-error-msg").html(),
|
||||
$t_html({defaultMessage: "Please specify at least one valid recipient"}),
|
||||
);
|
||||
|
||||
people.add_active_user(bob);
|
||||
compose_state.private_message_recipient("bob@example.com");
|
||||
assert.ok(compose_validate.validate());
|
||||
|
||||
people.deactivate(bob);
|
||||
assert.ok(!compose_validate.validate());
|
||||
assert.equal(
|
||||
$("#compose-error-msg").html(),
|
||||
$t_html({defaultMessage: "You cannot send messages to deactivated users."}),
|
||||
);
|
||||
|
||||
page_params.realm_is_zephyr_mirror_realm = true;
|
||||
assert.ok(compose_validate.validate());
|
||||
page_params.realm_is_zephyr_mirror_realm = false;
|
||||
|
||||
initialize_pm_pill();
|
||||
add_content_to_compose_box();
|
||||
compose_state.private_message_recipient("welcome-bot@example.com");
|
||||
assert.ok(compose_validate.validate());
|
||||
|
||||
// test validating stream messages
|
||||
compose_state.set_message_type("stream");
|
||||
compose_state.stream_name("");
|
||||
let empty_stream_error_rendered = false;
|
||||
mock_template("compose_banner/compose_banner.hbs", false, (data) => {
|
||||
assert.equal(data.classname, compose_error.CLASSNAMES.missing_stream);
|
||||
assert.equal(data.banner_text, $t({defaultMessage: "Please specify a stream."}));
|
||||
empty_stream_error_rendered = true;
|
||||
});
|
||||
assert.ok(!compose_validate.validate());
|
||||
assert.equal(
|
||||
$("#compose-error-msg").html(),
|
||||
$t_html({defaultMessage: "Please specify a stream"}),
|
||||
);
|
||||
assert.ok(empty_stream_error_rendered);
|
||||
|
||||
compose_state.stream_name("Denmark");
|
||||
page_params.realm_mandatory_topics = true;
|
||||
compose_state.topic("");
|
||||
assert.ok(!compose_validate.validate());
|
||||
let missing_topic_error_rendered = false;
|
||||
mock_template("compose_banner/compose_banner.hbs", false, (data) => {
|
||||
assert.equal(data.classname, compose_error.CLASSNAMES.topic_missing);
|
||||
assert.equal(
|
||||
$("#compose-error-msg").html(),
|
||||
$t_html({defaultMessage: "Topics are required in this organization"}),
|
||||
data.banner_text,
|
||||
$t({defaultMessage: "Topics are required in this organization."}),
|
||||
);
|
||||
missing_topic_error_rendered = true;
|
||||
});
|
||||
assert.ok(!compose_validate.validate());
|
||||
assert.ok(missing_topic_error_rendered);
|
||||
|
||||
missing_topic_error_rendered = false;
|
||||
compose_state.topic("(no topic)");
|
||||
assert.ok(!compose_validate.validate());
|
||||
assert.equal(
|
||||
$("#compose-error-msg").html(),
|
||||
$t_html({defaultMessage: "Topics are required in this organization"}),
|
||||
);
|
||||
assert.ok(missing_topic_error_rendered);
|
||||
});
|
||||
|
||||
test_ui("get_invalid_recipient_emails", ({override_rewire}) => {
|
||||
@@ -334,6 +355,7 @@ test_ui("validate_stream_message", ({override_rewire, mock_template}) => {
|
||||
// primarily used to get coverage over functions called from validate()
|
||||
// we are separating it up in different test. Though their relative position
|
||||
// of execution should not be changed.
|
||||
mock_banners();
|
||||
page_params.user_id = me.user_id;
|
||||
page_params.realm_mandatory_topics = false;
|
||||
const sub = {
|
||||
@@ -368,21 +390,30 @@ test_ui("validate_stream_message", ({override_rewire, mock_template}) => {
|
||||
assert.equal(compose_content, "compose_all_everyone_stub");
|
||||
assert.ok($("#compose-all-everyone").visible());
|
||||
|
||||
override_rewire(compose_validate, "wildcard_mention_allowed", () => false);
|
||||
assert.ok(!compose_validate.validate());
|
||||
let wildcards_not_allowed_rendered = false;
|
||||
mock_template("compose_banner/compose_banner.hbs", false, (data) => {
|
||||
assert.equal(data.classname, compose_error.CLASSNAMES.wildcards_not_allowed);
|
||||
assert.equal(
|
||||
$("#compose-error-msg").html(),
|
||||
$t_html({
|
||||
defaultMessage: "You do not have permission to use wildcard mentions in this stream.",
|
||||
data.banner_text,
|
||||
$t({
|
||||
defaultMessage:
|
||||
"You do not have permission to use wildcard mentions in this stream.",
|
||||
}),
|
||||
);
|
||||
wildcards_not_allowed_rendered = true;
|
||||
return "wildcard_warning_stub";
|
||||
});
|
||||
override_rewire(compose_validate, "wildcard_mention_allowed", () => false);
|
||||
assert.ok(!compose_validate.validate());
|
||||
assert.ok(wildcards_not_allowed_rendered);
|
||||
});
|
||||
|
||||
test_ui("test_validate_stream_message_post_policy_admin_only", () => {
|
||||
test_ui("test_validate_stream_message_post_policy_admin_only", ({mock_template}) => {
|
||||
// This test is in continuation with test_validate but it has been separated out
|
||||
// for better readability. Their relative position of execution should not be changed.
|
||||
// Although the position with respect to test_validate_stream_message does not matter
|
||||
// as different stream is used for this test.
|
||||
mock_banners();
|
||||
page_params.is_admin = false;
|
||||
const sub = {
|
||||
stream_id: 102,
|
||||
@@ -394,11 +425,20 @@ test_ui("test_validate_stream_message_post_policy_admin_only", () => {
|
||||
compose_state.topic("topic102");
|
||||
compose_state.stream_name("stream102");
|
||||
stream_data.add_sub(sub);
|
||||
assert.ok(!compose_validate.validate());
|
||||
|
||||
let banner_rendered = false;
|
||||
mock_template("compose_banner/compose_banner.hbs", false, (data) => {
|
||||
assert.equal(data.classname, compose_error.CLASSNAMES.no_post_permissions);
|
||||
assert.equal(
|
||||
$("#compose-error-msg").html(),
|
||||
$t_html({defaultMessage: "You do not have permission to post in this stream."}),
|
||||
data.banner_text,
|
||||
$t({
|
||||
defaultMessage: "You do not have permission to post in this stream.",
|
||||
}),
|
||||
);
|
||||
banner_rendered = true;
|
||||
});
|
||||
assert.ok(!compose_validate.validate());
|
||||
assert.ok(banner_rendered);
|
||||
|
||||
// Reset error message.
|
||||
compose_state.stream_name("social");
|
||||
@@ -408,14 +448,13 @@ test_ui("test_validate_stream_message_post_policy_admin_only", () => {
|
||||
|
||||
compose_state.topic("topic102");
|
||||
compose_state.stream_name("stream102");
|
||||
banner_rendered = false;
|
||||
assert.ok(!compose_validate.validate());
|
||||
assert.equal(
|
||||
$("#compose-error-msg").html(),
|
||||
$t_html({defaultMessage: "You do not have permission to post in this stream."}),
|
||||
);
|
||||
assert.ok(banner_rendered);
|
||||
});
|
||||
|
||||
test_ui("test_validate_stream_message_post_policy_moderators_only", () => {
|
||||
test_ui("test_validate_stream_message_post_policy_moderators_only", ({mock_template}) => {
|
||||
mock_banners();
|
||||
page_params.is_admin = false;
|
||||
page_params.is_moderator = false;
|
||||
page_params.is_guest = false;
|
||||
@@ -430,27 +469,29 @@ test_ui("test_validate_stream_message_post_policy_moderators_only", () => {
|
||||
compose_state.topic("topic104");
|
||||
compose_state.stream_name("stream104");
|
||||
stream_data.add_sub(sub);
|
||||
assert.ok(!compose_validate.validate());
|
||||
let banner_rendered = false;
|
||||
mock_template("compose_banner/compose_banner.hbs", false, (data) => {
|
||||
assert.equal(data.classname, compose_error.CLASSNAMES.no_post_permissions);
|
||||
assert.equal(
|
||||
$("#compose-error-msg").html(),
|
||||
$t_html({
|
||||
data.banner_text,
|
||||
$t({
|
||||
defaultMessage: "You do not have permission to post in this stream.",
|
||||
}),
|
||||
);
|
||||
|
||||
banner_rendered = true;
|
||||
});
|
||||
assert.ok(!compose_validate.validate());
|
||||
assert.ok(banner_rendered);
|
||||
// Reset error message.
|
||||
compose_state.stream_name("social");
|
||||
|
||||
page_params.is_guest = true;
|
||||
assert.equal(
|
||||
$("#compose-error-msg").html(),
|
||||
$t_html({
|
||||
defaultMessage: "You do not have permission to post in this stream.",
|
||||
}),
|
||||
);
|
||||
assert.ok(!compose_validate.validate());
|
||||
assert.ok(banner_rendered);
|
||||
});
|
||||
|
||||
test_ui("test_validate_stream_message_post_policy_full_members_only", () => {
|
||||
test_ui("test_validate_stream_message_post_policy_full_members_only", ({mock_template}) => {
|
||||
mock_banners();
|
||||
page_params.is_admin = false;
|
||||
page_params.is_guest = true;
|
||||
const sub = {
|
||||
@@ -463,19 +504,39 @@ test_ui("test_validate_stream_message_post_policy_full_members_only", () => {
|
||||
compose_state.topic("topic103");
|
||||
compose_state.stream_name("stream103");
|
||||
stream_data.add_sub(sub);
|
||||
assert.ok(!compose_validate.validate());
|
||||
let banner_rendered = false;
|
||||
mock_template("compose_banner/compose_banner.hbs", false, (data) => {
|
||||
assert.equal(data.classname, compose_error.CLASSNAMES.no_post_permissions);
|
||||
assert.equal(
|
||||
$("#compose-error-msg").html(),
|
||||
$t_html({defaultMessage: "You do not have permission to post in this stream."}),
|
||||
data.banner_text,
|
||||
$t({
|
||||
defaultMessage: "You do not have permission to post in this stream.",
|
||||
}),
|
||||
);
|
||||
banner_rendered = true;
|
||||
});
|
||||
assert.ok(!compose_validate.validate());
|
||||
assert.ok(banner_rendered);
|
||||
});
|
||||
|
||||
test_ui("test_check_overflow_text", () => {
|
||||
test_ui("test_check_overflow_text", ({mock_template}) => {
|
||||
mock_banners();
|
||||
page_params.max_message_length = 10000;
|
||||
|
||||
const $textarea = $("#compose-textarea");
|
||||
const $indicator = $("#compose_limit_indicator");
|
||||
const $send_button = $("#compose-send-button");
|
||||
let banner_rendered = false;
|
||||
mock_template("compose_banner/compose_banner.hbs", false, (data) => {
|
||||
assert.equal(data.classname, compose_error.CLASSNAMES.message_too_long);
|
||||
assert.equal(
|
||||
data.banner_text,
|
||||
$t({
|
||||
defaultMessage: "Message length shouldn't be greater than 10000 characters.",
|
||||
}),
|
||||
);
|
||||
banner_rendered = true;
|
||||
});
|
||||
|
||||
// Indicator should show red colored text
|
||||
$textarea.val("a".repeat(10000 + 1));
|
||||
@@ -483,52 +544,27 @@ test_ui("test_check_overflow_text", () => {
|
||||
assert.ok($indicator.hasClass("over_limit"));
|
||||
assert.equal($indicator.text(), "10001/10000");
|
||||
assert.ok($textarea.hasClass("over_limit"));
|
||||
assert.equal(
|
||||
$("#compose-error-msg").html(),
|
||||
"translated HTML: Message length shouldn't be greater than 10000 characters.",
|
||||
);
|
||||
assert.ok(banner_rendered);
|
||||
assert.ok($send_button.prop("disabled"));
|
||||
|
||||
$("#compose-send-status").stop = () => ({fadeOut() {}});
|
||||
|
||||
// Indicator should show orange colored text
|
||||
banner_rendered = false;
|
||||
$textarea.val("a".repeat(9000 + 1));
|
||||
compose_validate.check_overflow_text();
|
||||
assert.ok(!$indicator.hasClass("over_limit"));
|
||||
assert.equal($indicator.text(), "9001/10000");
|
||||
assert.ok(!$textarea.hasClass("over_limit"));
|
||||
assert.ok(!$send_button.prop("disabled"));
|
||||
assert.ok(!banner_rendered);
|
||||
|
||||
// Indicator must be empty
|
||||
banner_rendered = false;
|
||||
$textarea.val("a".repeat(9000));
|
||||
compose_validate.check_overflow_text();
|
||||
assert.ok(!$indicator.hasClass("over_limit"));
|
||||
assert.equal($indicator.text(), "");
|
||||
assert.ok(!$textarea.hasClass("over_limit"));
|
||||
});
|
||||
|
||||
test_ui("test_message_overflow", () => {
|
||||
page_params.max_message_length = 10000;
|
||||
|
||||
const sub = {
|
||||
stream_id: 101,
|
||||
name: "social",
|
||||
subscribed: true,
|
||||
};
|
||||
|
||||
stream_data.add_sub(sub);
|
||||
page_params.user_id = 30;
|
||||
const message = "a".repeat(10000 + 1);
|
||||
|
||||
compose_state.stream_name("social");
|
||||
compose_state.topic("priyam");
|
||||
$("#compose-textarea").val(message);
|
||||
|
||||
assert.ok(!compose_validate.validate());
|
||||
assert.equal($("#compose-error-msg").html(), "never-been-set");
|
||||
|
||||
$("#compose-textarea").val("a");
|
||||
assert.ok(compose_validate.validate());
|
||||
assert.ok(!banner_rendered);
|
||||
});
|
||||
|
||||
test_ui("needs_subscribe_warning", () => {
|
||||
@@ -767,7 +803,7 @@ test_ui("warn_if_mentioning_unsubscribed_user", ({override, override_rewire, moc
|
||||
test_ui("test warn_if_topic_resolved", ({override, mock_template}) => {
|
||||
mock_banners();
|
||||
$("#compose_banners .topic_resolved").length = 0;
|
||||
override(settings_data, "user_can_move_messages_between_streams", () => true);
|
||||
override(settings_data, "user_can_edit_topic_of_any_message", () => true);
|
||||
|
||||
let error_shown = false;
|
||||
mock_template("compose_banner/compose_banner.hbs", false, (data) => {
|
||||
|
||||
@@ -253,7 +253,11 @@ export function send_message(request = create_message_object()) {
|
||||
// If we're not local echo'ing messages, or if this message was not
|
||||
// locally echoed, show error in compose box
|
||||
if (!locally_echoed) {
|
||||
compose_error.show(_.escape(response), $("#compose-textarea"));
|
||||
compose_error.show_error_message(
|
||||
response,
|
||||
compose_error.CLASSNAMES.generic_compose_error,
|
||||
$("#compose-textarea"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -510,7 +514,11 @@ export function initialize() {
|
||||
|
||||
function failure(error_msg) {
|
||||
clear_invites();
|
||||
compose_error.show(_.escape(error_msg), $("#compose-textarea"));
|
||||
compose_error.show_error_message(
|
||||
error_msg,
|
||||
compose_error.CLASSNAMES.generic_compose_error,
|
||||
$("#compose-textarea"),
|
||||
);
|
||||
$(event.target).prop("disabled", true);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,63 @@
|
||||
import $ from "jquery";
|
||||
|
||||
import render_compose_banner from "../templates/compose_banner/compose_banner.hbs";
|
||||
import render_stream_does_not_exist_error from "../templates/compose_banner/stream_does_not_exist_error.hbs";
|
||||
|
||||
import * as common from "./common";
|
||||
|
||||
// banner types
|
||||
export const WARNING = "warning";
|
||||
export const ERROR = "error";
|
||||
|
||||
export const CLASSNAMES = {
|
||||
// warnings
|
||||
topic_resolved: "topic_resolved",
|
||||
// errors
|
||||
empty_message: "empty_message",
|
||||
wildcards_not_allowed: "wildcards_not_allowed",
|
||||
subscription_error: "subscription_error",
|
||||
stream_does_not_exist: "stream_does_not_exist",
|
||||
missing_stream: "missing_stream",
|
||||
no_post_permissions: "no_post_permissions",
|
||||
private_messages_disabled: "private_messages_disabled",
|
||||
missing_private_message_recipient: "missing_private_message_recipient",
|
||||
invalid_recipient: "invalid_recipient",
|
||||
invalid_recipients: "invalid_recipients",
|
||||
deactivated_user: "deactivated_user",
|
||||
message_too_long: "message_too_long",
|
||||
topic_missing: "topic_missing",
|
||||
zephyr_not_running: "zephyr_not_running",
|
||||
generic_compose_error: "generic_compose_error",
|
||||
};
|
||||
|
||||
// TODO: Replace with compose_ui.hide_compose_spinner() when it is converted to ts.
|
||||
function hide_compose_spinner(): void {
|
||||
$("#compose-send-button .loader").hide();
|
||||
$("#compose-send-button span").show();
|
||||
$("#compose-send-button").removeClass("disable-btn");
|
||||
}
|
||||
|
||||
export function show_error_message(message: string, classname: string, $bad_input?: JQuery): void {
|
||||
$(`#compose_banners .${classname}`).remove();
|
||||
|
||||
const new_row = render_compose_banner({
|
||||
banner_type: ERROR,
|
||||
stream_id: null,
|
||||
topic_name: null,
|
||||
banner_text: message,
|
||||
button_text: null,
|
||||
classname,
|
||||
});
|
||||
const $compose_banner_area = $("#compose_banners");
|
||||
$compose_banner_area.append(new_row);
|
||||
|
||||
hide_compose_spinner();
|
||||
|
||||
if ($bad_input !== undefined) {
|
||||
$bad_input.trigger("focus").trigger("select");
|
||||
}
|
||||
}
|
||||
|
||||
export function show(error_html: string, $bad_input?: JQuery, alert_class = "alert-error"): void {
|
||||
$("#compose-send-status")
|
||||
.removeClass(common.status_classes)
|
||||
@@ -17,16 +65,28 @@ export function show(error_html: string, $bad_input?: JQuery, alert_class = "ale
|
||||
.stop(true)
|
||||
.fadeTo(0, 1);
|
||||
$("#compose-error-msg").html(error_html);
|
||||
// TODO: Replace with compose_ui.hide_compose_spinner() when it is converted to ts.
|
||||
$("#compose-send-button .loader").hide();
|
||||
$("#compose-send-button span").show();
|
||||
$("#compose-send-button").removeClass("disable-btn");
|
||||
hide_compose_spinner();
|
||||
|
||||
if ($bad_input !== undefined) {
|
||||
$bad_input.trigger("focus").trigger("select");
|
||||
}
|
||||
}
|
||||
|
||||
export function show_stream_does_not_exist_error(stream_name: string): void {
|
||||
// Remove any existing banners with this warning.
|
||||
$(`#compose_banners .${CLASSNAMES.stream_does_not_exist}`).remove();
|
||||
|
||||
const new_row = render_stream_does_not_exist_error({
|
||||
banner_type: ERROR,
|
||||
stream_name,
|
||||
classname: CLASSNAMES.stream_does_not_exist,
|
||||
});
|
||||
const $compose_banner_area = $("#compose_banners");
|
||||
$compose_banner_area.append(new_row);
|
||||
hide_compose_spinner();
|
||||
$("#stream_message_recipient_stream").trigger("focus").trigger("select");
|
||||
}
|
||||
|
||||
export function show_not_subscribed(error_html: string, $bad_input?: JQuery): void {
|
||||
show(error_html, $bad_input, "home-error-bar");
|
||||
$(".compose-send-status-close").hide();
|
||||
|
||||
@@ -12,7 +12,7 @@ import * as compose_error from "./compose_error";
|
||||
import * as compose_pm_pill from "./compose_pm_pill";
|
||||
import * as compose_state from "./compose_state";
|
||||
import * as compose_ui from "./compose_ui";
|
||||
import {$t, $t_html} from "./i18n";
|
||||
import {$t} from "./i18n";
|
||||
import {page_params} from "./page_params";
|
||||
import * as peer_data from "./peer_data";
|
||||
import * as people from "./people";
|
||||
@@ -346,11 +346,12 @@ function validate_stream_message_mentions(stream_id) {
|
||||
// stream, check if they permission to do so.
|
||||
if (wildcard_mention !== null && stream_count > wildcard_mention_large_stream_threshold) {
|
||||
if (!wildcard_mention_allowed()) {
|
||||
compose_error.show(
|
||||
$t_html({
|
||||
compose_error.show_error_message(
|
||||
$t({
|
||||
defaultMessage:
|
||||
"You do not have permission to use wildcard mentions in this stream.",
|
||||
}),
|
||||
compose_error.CLASSNAMES.wildcards_not_allowed,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -377,26 +378,14 @@ function validate_stream_message_mentions(stream_id) {
|
||||
}
|
||||
|
||||
export function validation_error(error_type, stream_name) {
|
||||
let response;
|
||||
|
||||
switch (error_type) {
|
||||
case "does-not-exist":
|
||||
response = $t_html(
|
||||
{
|
||||
defaultMessage:
|
||||
"<p>The stream <b>{stream_name}</b> does not exist.</p><p>Manage your subscriptions <z-link>on your Streams page</z-link>.</p>",
|
||||
},
|
||||
{
|
||||
stream_name,
|
||||
"z-link": (content_html) =>
|
||||
`<a href='#streams/all'>${content_html.join("")}</a>`,
|
||||
},
|
||||
);
|
||||
compose_error.show(response, $("#stream_message_recipient_stream"));
|
||||
compose_error.show_stream_does_not_exist_error(stream_name);
|
||||
return false;
|
||||
case "error":
|
||||
compose_error.show(
|
||||
$t_html({defaultMessage: "Error checking subscription"}),
|
||||
compose_error.show_error_message(
|
||||
$t({defaultMessage: "Error checking subscription."}),
|
||||
compose_error.CLASSNAMES.subscription_error,
|
||||
$("#stream_message_recipient_stream"),
|
||||
);
|
||||
return false;
|
||||
@@ -424,8 +413,9 @@ export function validate_stream_message_address_info(stream_name) {
|
||||
function validate_stream_message() {
|
||||
const stream_name = compose_state.stream_name();
|
||||
if (stream_name === "") {
|
||||
compose_error.show(
|
||||
$t_html({defaultMessage: "Please specify a stream"}),
|
||||
compose_error.show_error_message(
|
||||
$t({defaultMessage: "Please specify a stream."}),
|
||||
compose_error.CLASSNAMES.missing_stream,
|
||||
$("#stream_message_recipient_stream"),
|
||||
);
|
||||
return false;
|
||||
@@ -436,8 +426,9 @@ function validate_stream_message() {
|
||||
// TODO: We plan to migrate the empty topic to only using the
|
||||
// `""` representation for i18n reasons, but have not yet done so.
|
||||
if (topic === "" || topic === "(no topic)") {
|
||||
compose_error.show(
|
||||
$t_html({defaultMessage: "Topics are required in this organization"}),
|
||||
compose_error.show_error_message(
|
||||
$t({defaultMessage: "Topics are required in this organization."}),
|
||||
compose_error.CLASSNAMES.topic_missing,
|
||||
$("#stream_message_recipient_topic"),
|
||||
);
|
||||
return false;
|
||||
@@ -450,10 +441,11 @@ function validate_stream_message() {
|
||||
}
|
||||
|
||||
if (!stream_data.can_post_messages_in_stream(sub)) {
|
||||
compose_error.show(
|
||||
$t_html({
|
||||
compose_error.show_error_message(
|
||||
$t({
|
||||
defaultMessage: "You do not have permission to post in this stream.",
|
||||
}),
|
||||
compose_error.CLASSNAMES.no_post_permissions,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -484,16 +476,18 @@ function validate_private_message() {
|
||||
(user_ids.length !== 1 || !people.get_by_user_id(user_ids[0]).is_bot)
|
||||
) {
|
||||
// Unless we're composing to a bot
|
||||
compose_error.show(
|
||||
$t_html({defaultMessage: "Private messages are disabled in this organization."}),
|
||||
compose_error.show_error_message(
|
||||
$t({defaultMessage: "Private messages are disabled in this organization."}),
|
||||
compose_error.CLASSNAMES.private_messages_disabled,
|
||||
$("#private_message_recipient"),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (compose_state.private_message_recipient().length === 0) {
|
||||
compose_error.show(
|
||||
$t_html({defaultMessage: "Please specify at least one valid recipient"}),
|
||||
compose_error.show_error_message(
|
||||
$t({defaultMessage: "Please specify at least one valid recipient."}),
|
||||
compose_error.CLASSNAMES.missing_private_message_recipient,
|
||||
$("#private_message_recipient"),
|
||||
);
|
||||
return false;
|
||||
@@ -507,15 +501,17 @@ function validate_private_message() {
|
||||
let context = {};
|
||||
if (invalid_recipients.length === 1) {
|
||||
context = {recipient: invalid_recipients.join(",")};
|
||||
compose_error.show(
|
||||
$t_html({defaultMessage: "The recipient {recipient} is not valid"}, context),
|
||||
compose_error.show_error_message(
|
||||
$t({defaultMessage: "The recipient {recipient} is not valid."}, context),
|
||||
compose_error.CLASSNAMES.invalid_recipient,
|
||||
$("#private_message_recipient"),
|
||||
);
|
||||
return false;
|
||||
} else if (invalid_recipients.length > 1) {
|
||||
context = {recipients: invalid_recipients.join(",")};
|
||||
compose_error.show(
|
||||
$t_html({defaultMessage: "The recipients {recipients} are not valid"}, context),
|
||||
compose_error.show_error_message(
|
||||
$t({defaultMessage: "The recipients {recipients} are not valid."}, context),
|
||||
compose_error.CLASSNAMES.invalid_recipients,
|
||||
$("#private_message_recipient"),
|
||||
);
|
||||
return false;
|
||||
@@ -524,11 +520,9 @@ function validate_private_message() {
|
||||
for (const user_id of user_ids) {
|
||||
if (!people.is_person_active(user_id)) {
|
||||
context = {full_name: people.get_by_user_id(user_id).full_name};
|
||||
compose_error.show(
|
||||
$t_html(
|
||||
{defaultMessage: "You cannot send messages to deactivated users."},
|
||||
context,
|
||||
),
|
||||
compose_error.show_error_message(
|
||||
$t({defaultMessage: "You cannot send messages to deactivated users."}, context),
|
||||
compose_error.CLASSNAMES.deactivated_user,
|
||||
$("#private_message_recipient"),
|
||||
);
|
||||
|
||||
@@ -551,14 +545,15 @@ export function check_overflow_text() {
|
||||
$indicator.addClass("over_limit");
|
||||
$("#compose-textarea").addClass("over_limit");
|
||||
$indicator.text(text.length + "/" + max_length);
|
||||
compose_error.show(
|
||||
$t_html(
|
||||
compose_error.show_error_message(
|
||||
$t(
|
||||
{
|
||||
defaultMessage:
|
||||
"Message length shouldn't be greater than {max_length} characters.",
|
||||
},
|
||||
{max_length},
|
||||
),
|
||||
compose_error.CLASSNAMES.message_too_long,
|
||||
);
|
||||
$("#compose-send-button").prop("disabled", true);
|
||||
} else if (text.length > 0.9 * max_length) {
|
||||
@@ -567,17 +562,13 @@ export function check_overflow_text() {
|
||||
$indicator.text(text.length + "/" + max_length);
|
||||
|
||||
$("#compose-send-button").prop("disabled", false);
|
||||
if ($("#compose-send-status").hasClass("alert-error")) {
|
||||
$("#compose-send-status").stop(true).fadeOut();
|
||||
}
|
||||
$(`#compose_banners .${compose_error.CLASSNAMES.message_too_long}`).remove();
|
||||
} else {
|
||||
$indicator.text("");
|
||||
$("#compose-textarea").removeClass("over_limit");
|
||||
|
||||
$("#compose-send-button").prop("disabled", false);
|
||||
if ($("#compose-send-status").hasClass("alert-error")) {
|
||||
$("#compose-send-status").stop(true).fadeOut();
|
||||
}
|
||||
$(`#compose_banners .${compose_error.CLASSNAMES.message_too_long}`).remove();
|
||||
}
|
||||
|
||||
return text.length;
|
||||
@@ -598,20 +589,23 @@ export function validate() {
|
||||
// Avoid showing an error message when "enter sends" is enabled,
|
||||
// as it is more likely that the user has hit "Enter" accidentally.
|
||||
if (!user_settings.enter_sends) {
|
||||
compose_error.show(
|
||||
$t_html({defaultMessage: "You have nothing to send!"}),
|
||||
compose_error.show_error_message(
|
||||
$t({defaultMessage: "You have nothing to send!"}),
|
||||
compose_error.CLASSNAMES.empty_message,
|
||||
$("#compose-textarea"),
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
$(`#compose_banners .${compose_error.CLASSNAMES.empty_message}`).remove();
|
||||
|
||||
if ($("#zephyr-mirror-error").is(":visible")) {
|
||||
compose_error.show(
|
||||
$t_html({
|
||||
compose_error.show_error_message(
|
||||
$t({
|
||||
defaultMessage:
|
||||
"You need to be running Zephyr mirroring in order to send messages!",
|
||||
}),
|
||||
compose_error.CLASSNAMES.zephyr_not_running,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import $ from "jquery";
|
||||
import _ from "lodash";
|
||||
|
||||
import * as channel from "./channel";
|
||||
import * as compose from "./compose";
|
||||
@@ -72,7 +71,11 @@ export function schedule_message(request = compose.create_message_object()) {
|
||||
}
|
||||
|
||||
if (error_message) {
|
||||
compose_error.show(error_message, $("#compose-textarea"));
|
||||
compose_error.show_error_message(
|
||||
error_message,
|
||||
compose_error.CLASSNAMES.generic_compose_error,
|
||||
$("#compose-textarea"),
|
||||
);
|
||||
$("#compose-textarea").prop("disabled", false);
|
||||
return;
|
||||
}
|
||||
@@ -96,7 +99,11 @@ export function schedule_message(request = compose.create_message_object()) {
|
||||
};
|
||||
const error = function (response) {
|
||||
$("#compose-textarea").prop("disabled", false);
|
||||
compose_error.show(_.escape(response), $("#compose-textarea"));
|
||||
compose_error.show_error_message(
|
||||
response,
|
||||
compose_error.CLASSNAMES.generic_compose_error,
|
||||
$("#compose-textarea"),
|
||||
);
|
||||
};
|
||||
/* We are adding a disable on compose under this block because we
|
||||
want slash commands to be blocking in nature. */
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import $ from "jquery";
|
||||
|
||||
import * as channel from "./channel";
|
||||
import * as common from "./common";
|
||||
import * as compose_error from "./compose_error";
|
||||
import * as dark_theme from "./dark_theme";
|
||||
import * as feedback_widget from "./feedback_widget";
|
||||
import {$t} from "./i18n";
|
||||
@@ -50,12 +48,7 @@ export function send(opts) {
|
||||
export function tell_user(msg) {
|
||||
// This is a bit hacky, but we don't have a super easy API now
|
||||
// for just telling users stuff.
|
||||
$("#compose-send-status")
|
||||
.removeClass(common.status_classes)
|
||||
.addClass("alert-error")
|
||||
.stop(true)
|
||||
.fadeTo(0, 1);
|
||||
$("#compose-error-msg").text(msg);
|
||||
compose_error.show_error_message(msg, compose_error.CLASSNAMES.generic_compose_error);
|
||||
}
|
||||
|
||||
export function switch_to_light_theme() {
|
||||
|
||||
@@ -348,6 +348,37 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.error {
|
||||
background-color: hsl(4, 35%, 90%);
|
||||
border-color: hsla(3, 57%, 33%, 0.4);
|
||||
color: hsl(4, 58%, 33%);
|
||||
|
||||
.compose_banner_close_button {
|
||||
color: hsla(4, 58%, 33%, 0.5);
|
||||
|
||||
&:hover {
|
||||
color: hsl(4, 58%, 33%);
|
||||
}
|
||||
|
||||
&:active {
|
||||
color: hsla(4, 58%, 33%, 0.75);
|
||||
}
|
||||
}
|
||||
|
||||
.compose_banner_action_button {
|
||||
background-color: hsla(3, 57%, 33%, 0.1);
|
||||
color: inherit;
|
||||
|
||||
&:hover {
|
||||
background-color: hsla(3, 57%, 33%, 0.12);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: hsla(3, 57%, 33%, 0.15);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.compose_invite_user,
|
||||
|
||||
@@ -202,6 +202,37 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.error {
|
||||
background-color: hsl(0, 60%, 19%);
|
||||
border-color: hsla(3, 73%, 74%, 0.4);
|
||||
color: hsl(3, 73%, 74%);
|
||||
|
||||
.compose_banner_close_button {
|
||||
color: hsla(3, 73%, 74%, 0.5);
|
||||
|
||||
&:hover {
|
||||
color: hsl(3, 73%, 74%);
|
||||
}
|
||||
|
||||
&:active {
|
||||
color: hsl(3, 73%, 74%, 0.75);
|
||||
}
|
||||
}
|
||||
|
||||
.compose_banner_action_button {
|
||||
background-color: hsla(3, 73%, 74%, 0.1);
|
||||
color: inherit;
|
||||
|
||||
&:hover {
|
||||
background: hsla(3, 73%, 74%, 0.15);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: hsla(3, 73%, 74%, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.message_embed .data-container::after {
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
class="compose_banner {{banner_type}} {{classname}}"
|
||||
{{#if stream_id}}data-stream-id="{{stream_id}}"{{/if}}
|
||||
{{#if topic_name}}data-topic-name="{{topic_name}}"{{/if}}>
|
||||
{{#if banner_text}}
|
||||
<p class="banner_content">{{banner_text}}</p>
|
||||
{{else}}
|
||||
<div class="banner_content">{{> @partial-block}}</div>
|
||||
{{/if}}
|
||||
{{#if button_text}}
|
||||
<button class="compose_banner_action_button" >{{button_text}}</button>
|
||||
{{/if}}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{{#> compose_banner }}
|
||||
<p>
|
||||
{{#tr}}
|
||||
The stream <b>#{stream_name}</b> does not exist. Manage your subscriptions
|
||||
<z-link>on your Streams page</z-link>.
|
||||
{{#*inline "z-link"}}<a href='#streams/all'>{{> @partial-block}}</a>{{/inline}}
|
||||
{{/tr}}
|
||||
</p>
|
||||
{{/compose_banner}}
|
||||
Reference in New Issue
Block a user