mirror of
https://github.com/zulip/zulip.git
synced 2025-11-12 18:06:44 +00:00
compose: Restore the last draft when compose box is opened.
Now when the user opens a narrow that has a draft saved for that particular conversation, the draft will automatically be restored in the compose box. This will make it easy to return to a draft after clicking away, and also will make it less confusing when people close the compose box by accident. Note that this only restores the draft when there is a full recipient specified (stream and topic, or at least one PM recipient). Fixes part of #18555. Fixes #11218 and #17396.
This commit is contained in:
@@ -43,6 +43,23 @@ async function create_stream_message_draft(page: Page): Promise<void> {
|
|||||||
await page.click("#compose_close");
|
await page.click("#compose_close");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function test_restore_stream_message_draft_by_opening_compose_box(page: Page): Promise<void> {
|
||||||
|
await page.click(".search_icon");
|
||||||
|
await page.waitForSelector("#search_query", {visible: true});
|
||||||
|
await common.select_item_via_typeahead(page, "#search_query", "stream:Denmark topic:tests", "");
|
||||||
|
|
||||||
|
await page.click("#left_bar_compose_reply_button_big");
|
||||||
|
await page.waitForSelector("#send_message_form", {visible: true});
|
||||||
|
|
||||||
|
await common.check_compose_state(page, {
|
||||||
|
stream: "Denmark",
|
||||||
|
topic: "tests",
|
||||||
|
content: "Test stream message.",
|
||||||
|
});
|
||||||
|
await page.click("#compose_close");
|
||||||
|
await page.waitForSelector("#send_message_form", {visible: false});
|
||||||
|
}
|
||||||
|
|
||||||
async function create_private_message_draft(page: Page): Promise<void> {
|
async function create_private_message_draft(page: Page): Promise<void> {
|
||||||
console.log("Creating direct message draft");
|
console.log("Creating direct message draft");
|
||||||
await page.keyboard.press("KeyX");
|
await page.keyboard.press("KeyX");
|
||||||
@@ -50,7 +67,17 @@ async function create_private_message_draft(page: Page): Promise<void> {
|
|||||||
await common.fill_form(page, "form#send_message_form", {content: "Test direct message."});
|
await common.fill_form(page, "form#send_message_form", {content: "Test direct message."});
|
||||||
await common.pm_recipient.set(page, "cordelia@zulip.com");
|
await common.pm_recipient.set(page, "cordelia@zulip.com");
|
||||||
await common.pm_recipient.set(page, "hamlet@zulip.com");
|
await common.pm_recipient.set(page, "hamlet@zulip.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function test_restore_private_message_draft_by_opening_composebox(page: Page): Promise<void> {
|
||||||
|
await page.click("#left_bar_compose_reply_button_big");
|
||||||
|
await page.waitForSelector("#private_message_recipient", {visible: true});
|
||||||
|
|
||||||
|
await common.check_form_contents(page, "form#send_message_form", {
|
||||||
|
content: "Test direct message.",
|
||||||
|
});
|
||||||
await page.click("#compose_close");
|
await page.click("#compose_close");
|
||||||
|
await page.waitForSelector("#private_message_recipient", {visible: false});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function open_compose_markdown_preview(page: Page): Promise<void> {
|
async function open_compose_markdown_preview(page: Page): Promise<void> {
|
||||||
@@ -99,7 +126,7 @@ async function test_previously_created_drafts_rendered(page: Page): Promise<void
|
|||||||
page,
|
page,
|
||||||
"#drafts_table .overlay-message-row .message_header_private_message .stream_label",
|
"#drafts_table .overlay-message-row .message_header_private_message .stream_label",
|
||||||
),
|
),
|
||||||
"You and Cordelia, Lear's daughter, King Hamlet",
|
"You and King Hamlet, Cordelia, Lear's daughter",
|
||||||
);
|
);
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
await common.get_text_from_selector(
|
await common.get_text_from_selector(
|
||||||
@@ -174,7 +201,7 @@ async function test_restore_private_message_draft_via_draft_overlay(page: Page):
|
|||||||
});
|
});
|
||||||
const cordelia_internal_email = await common.get_internal_email_from_name(page, "cordelia");
|
const cordelia_internal_email = await common.get_internal_email_from_name(page, "cordelia");
|
||||||
const hamlet_internal_email = await common.get_internal_email_from_name(page, "hamlet");
|
const hamlet_internal_email = await common.get_internal_email_from_name(page, "hamlet");
|
||||||
await common.pm_recipient.expect(page, `${cordelia_internal_email},${hamlet_internal_email}`);
|
await common.pm_recipient.expect(page, `${hamlet_internal_email},${cordelia_internal_email}`);
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
await common.get_text_from_selector(page, "title"),
|
await common.get_text_from_selector(page, "title"),
|
||||||
"Cordelia, Lear's daughter, King Hamlet - Zulip Dev - Zulip",
|
"Cordelia, Lear's daughter, King Hamlet - Zulip Dev - Zulip",
|
||||||
@@ -259,7 +286,22 @@ async function drafts_test(page: Page): Promise<void> {
|
|||||||
await test_empty_drafts(page);
|
await test_empty_drafts(page);
|
||||||
|
|
||||||
await create_stream_message_draft(page);
|
await create_stream_message_draft(page);
|
||||||
|
await test_restore_stream_message_draft_by_opening_compose_box(page);
|
||||||
|
|
||||||
|
// Send a private message so that the draft we create is
|
||||||
|
// for an existing conversation.
|
||||||
|
await common.send_message(page, "private", {
|
||||||
|
recipient: "cordelia@zulip.com, hamlet@zulip.com",
|
||||||
|
content: "howdy doo",
|
||||||
|
outside_view: true,
|
||||||
|
});
|
||||||
await create_private_message_draft(page);
|
await create_private_message_draft(page);
|
||||||
|
// Narrow to the conversation so that the compose box will restore it,
|
||||||
|
// then close and try restoring it by opening the composebox again.
|
||||||
|
await page.click("#compose .narrow_to_compose_recipients");
|
||||||
|
await page.click("#compose_close");
|
||||||
|
await test_restore_private_message_draft_by_opening_composebox(page);
|
||||||
|
|
||||||
await open_drafts_after_markdown_preview(page);
|
await open_drafts_after_markdown_preview(page);
|
||||||
await test_previously_created_drafts_rendered(page);
|
await test_previously_created_drafts_rendered(page);
|
||||||
|
|
||||||
|
|||||||
@@ -302,6 +302,20 @@ export function start(raw_opts: ComposeActionsStartOpts): void {
|
|||||||
opts.private_message_recipient.replaceAll(/,\s*/g, ", "),
|
opts.private_message_recipient.replaceAll(/,\s*/g, ", "),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// If we're not explicitly opening a different draft, restore the last
|
||||||
|
// saved draft (if it exists).
|
||||||
|
if (
|
||||||
|
!opts.content &&
|
||||||
|
opts.draft_id === undefined &&
|
||||||
|
compose_state.message_content().length === 0
|
||||||
|
) {
|
||||||
|
const possible_last_draft = drafts.get_last_draft_based_on_compose_state();
|
||||||
|
if (possible_last_draft !== undefined) {
|
||||||
|
opts.draft_id = possible_last_draft.id;
|
||||||
|
opts.content = possible_last_draft.content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (opts.content !== undefined) {
|
if (opts.content !== undefined) {
|
||||||
compose_ui.insert_and_scroll_into_view(opts.content, $("textarea#compose-textarea"), true);
|
compose_ui.insert_and_scroll_into_view(opts.content, $("textarea#compose-textarea"), true);
|
||||||
$(".compose_control_button_container:has(.add-poll)").addClass("disabled-on-hover");
|
$(".compose_control_button_container:has(.add-poll)").addClass("disabled-on-hover");
|
||||||
|
|||||||
@@ -493,6 +493,20 @@ export function filter_drafts_by_compose_box_and_recipient(
|
|||||||
return _.pick(drafts, narrow_drafts_ids);
|
return _.pick(drafts, narrow_drafts_ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function get_last_draft_based_on_compose_state(): LocalStorageDraftWithId | undefined {
|
||||||
|
const current_drafts = draft_model.get();
|
||||||
|
const drafts_map_for_compose_state = filter_drafts_by_compose_box_and_recipient(current_drafts);
|
||||||
|
const drafts_for_compose_state = Object.entries(drafts_map_for_compose_state).map(
|
||||||
|
([draft_id, draft]) => ({
|
||||||
|
...draft,
|
||||||
|
id: draft_id,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
return drafts_for_compose_state
|
||||||
|
.sort((draft_a, draft_b) => draft_a.updatedAt - draft_b.updatedAt)
|
||||||
|
.pop();
|
||||||
|
}
|
||||||
|
|
||||||
export function remove_old_drafts(): void {
|
export function remove_old_drafts(): void {
|
||||||
const old_date = subDays(new Date(), DRAFT_LIFETIME).getTime();
|
const old_date = subDays(new Date(), DRAFT_LIFETIME).getTime();
|
||||||
const drafts = draft_model.get();
|
const drafts = draft_model.get();
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ mock_esm("../src/reload_state", {
|
|||||||
mock_esm("../src/drafts", {
|
mock_esm("../src/drafts", {
|
||||||
update_draft: noop,
|
update_draft: noop,
|
||||||
update_compose_draft_count: noop,
|
update_compose_draft_count: noop,
|
||||||
|
get_last_draft_based_on_compose_state: noop,
|
||||||
});
|
});
|
||||||
mock_esm("../src/unread_ops", {
|
mock_esm("../src/unread_ops", {
|
||||||
notify_server_message_read: noop,
|
notify_server_message_read: noop,
|
||||||
|
|||||||
@@ -65,9 +65,10 @@ const drafts_overlay_ui = zrequire("drafts_overlay_ui");
|
|||||||
const timerender = zrequire("timerender");
|
const timerender = zrequire("timerender");
|
||||||
|
|
||||||
const mock_current_timestamp = 1234;
|
const mock_current_timestamp = 1234;
|
||||||
|
const stream_id = 30;
|
||||||
|
|
||||||
const draft_1 = {
|
const draft_1 = {
|
||||||
stream_id: 30,
|
stream_id,
|
||||||
topic: "topic",
|
topic: "topic",
|
||||||
type: "stream",
|
type: "stream",
|
||||||
content: "Test stream message",
|
content: "Test stream message",
|
||||||
@@ -81,7 +82,7 @@ const draft_2 = {
|
|||||||
updatedAt: mock_current_timestamp,
|
updatedAt: mock_current_timestamp,
|
||||||
};
|
};
|
||||||
const short_msg = {
|
const short_msg = {
|
||||||
stream_id: 30,
|
stream_id,
|
||||||
topic: "topic",
|
topic: "topic",
|
||||||
type: "stream",
|
type: "stream",
|
||||||
content: "a",
|
content: "a",
|
||||||
|
|||||||
Reference in New Issue
Block a user