diff --git a/web/src/compose_actions.ts b/web/src/compose_actions.ts index 032cbfaef8..19cb224eb6 100644 --- a/web/src/compose_actions.ts +++ b/web/src/compose_actions.ts @@ -312,7 +312,7 @@ export function start(raw_opts: ComposeActionsStartOpts): void { compose_state.message_content().length === 0 && !opts.keep_composebox_empty ) { - const possible_last_draft = drafts.get_last_draft_based_on_compose_state(); + const possible_last_draft = drafts.get_last_restorable_draft_based_on_compose_state(); if (possible_last_draft !== undefined) { opts.draft_id = possible_last_draft.id; // Add a space at the end so that if the user starts typing diff --git a/web/src/drafts.ts b/web/src/drafts.ts index 166950c154..c619a1c72d 100644 --- a/web/src/drafts.ts +++ b/web/src/drafts.ts @@ -31,11 +31,17 @@ function getTimestamp(): number { return Date.now(); } +const CURRENT_DRAFT_VERSION = 1; + const draft_schema = z.intersection( z.object({ content: z.string(), updatedAt: z.number(), is_sending_saving: z.boolean().default(false), + // `drafts_version` is 0 for drafts that aren't auto-restored + // and 1 for drafts created since that change, to avoid a flood + // of old drafts showing up when this feature was introduced. + drafts_version: z.number().default(0), }), z.discriminatedUnion("type", [ z.object({ @@ -62,6 +68,7 @@ const possibly_buggy_draft_schema = z.intersection( content: z.string(), updatedAt: z.number(), is_sending_saving: z.boolean().default(false), + drafts_version: z.number().default(0), }), z.discriminatedUnion("type", [ z.object({ @@ -306,6 +313,7 @@ export function snapshot_message(): LocalStorageDraft | undefined { reply_to: recipient, private_message_recipient: recipient, is_sending_saving: false, + drafts_version: CURRENT_DRAFT_VERSION, }; } assert(message.type === "stream"); @@ -315,6 +323,7 @@ export function snapshot_message(): LocalStorageDraft | undefined { stream_id: compose_state.stream_id(), topic: compose_state.topic(), is_sending_saving: false, + drafts_version: CURRENT_DRAFT_VERSION, }; } @@ -405,6 +414,9 @@ export function update_draft(opts: UpdateDraftOptions = {}): string | undefined draft.is_sending_saving = old_draft ? old_draft.is_sending_saving : false; } + // Now that it's been updated, we consider it to be the most recent version. + draft.drafts_version = CURRENT_DRAFT_VERSION; + if (draft_id !== undefined) { // We don't save multiple drafts of the same message; // just update the existing draft. @@ -509,7 +521,9 @@ export function filter_drafts_by_compose_box_and_recipient( return _.pick(drafts, narrow_drafts_ids); } -export function get_last_draft_based_on_compose_state(): LocalStorageDraftWithId | undefined { +export function get_last_restorable_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( @@ -520,7 +534,7 @@ export function get_last_draft_based_on_compose_state(): LocalStorageDraftWithId ); return drafts_for_compose_state .sort((draft_a, draft_b) => draft_a.updatedAt - draft_b.updatedAt) - .filter((draft) => !draft.is_sending_saving) + .filter((draft) => !draft.is_sending_saving && draft.drafts_version >= 1) .pop(); } diff --git a/web/tests/compose_actions.test.js b/web/tests/compose_actions.test.js index c63208b200..990335f0c3 100644 --- a/web/tests/compose_actions.test.js +++ b/web/tests/compose_actions.test.js @@ -45,7 +45,7 @@ mock_esm("../src/reload_state", { mock_esm("../src/drafts", { update_draft: noop, update_compose_draft_count: noop, - get_last_draft_based_on_compose_state: noop, + get_last_restorable_draft_based_on_compose_state: noop, }); mock_esm("../src/unread_ops", { notify_server_message_read: noop, diff --git a/web/tests/drafts.test.js b/web/tests/drafts.test.js index f5cb068f97..51dd461cb4 100644 --- a/web/tests/drafts.test.js +++ b/web/tests/drafts.test.js @@ -74,6 +74,7 @@ const draft_1 = { content: "Test stream message", updatedAt: mock_current_timestamp, is_sending_saving: false, + drafts_version: 1, }; const draft_2 = { private_message_recipient: "aaron@zulip.com", @@ -82,6 +83,7 @@ const draft_2 = { content: "Test direct message", updatedAt: mock_current_timestamp, is_sending_saving: false, + drafts_version: 1, }; const short_msg = { stream_id, @@ -90,6 +92,7 @@ const short_msg = { content: "a", updatedAt: mock_current_timestamp, is_sending_saving: false, + drafts_version: 1, }; function test(label, f) { @@ -267,6 +270,7 @@ test("remove_old_drafts", ({override_rewire}) => { content: "Test stream message", updatedAt: Date.now(), is_sending_saving: false, + drafts_version: 1, }; const draft_4 = { private_message_recipient: "aaron@zulip.com", @@ -275,6 +279,7 @@ test("remove_old_drafts", ({override_rewire}) => { content: "Test direct message", updatedAt: new Date().setDate(-30), is_sending_saving: false, + drafts_version: 1, }; const draft_model = drafts.draft_model; const ls = localstorage(); @@ -469,6 +474,7 @@ test("format_drafts", ({override, override_rewire, mock_template}) => { stream_id: 30, updatedAt: feb12().getTime(), is_sending_saving: false, + drafts_version: 1, }; const draft_2 = { private_message_recipient: "aaron@zulip.com", @@ -477,6 +483,7 @@ test("format_drafts", ({override, override_rewire, mock_template}) => { content: "Test direct message", updatedAt: date(-1), is_sending_saving: false, + drafts_version: 1, }; const draft_3 = { topic: "topic", @@ -485,6 +492,7 @@ test("format_drafts", ({override, override_rewire, mock_template}) => { content: "Test stream message 2", updatedAt: date(-10), is_sending_saving: false, + drafts_version: 1, }; const draft_4 = { private_message_recipient: "aaron@zulip.com", @@ -493,6 +501,7 @@ test("format_drafts", ({override, override_rewire, mock_template}) => { content: "Test direct message 2", updatedAt: date(-5), is_sending_saving: false, + drafts_version: 1, }; const draft_5 = { private_message_recipient: "aaron@zulip.com", @@ -501,6 +510,7 @@ test("format_drafts", ({override, override_rewire, mock_template}) => { content: "Test direct message 3", updatedAt: date(-2), is_sending_saving: false, + drafts_version: 1, }; const expected = [ @@ -631,6 +641,7 @@ test("filter_drafts", ({override, override_rewire, mock_template}) => { stream_id: 30, updatedAt: feb12().getTime(), is_sending_saving: false, + drafts_version: 1, }; const pm_draft_1 = { private_message_recipient: "aaron@zulip.com", @@ -639,6 +650,7 @@ test("filter_drafts", ({override, override_rewire, mock_template}) => { content: "Test direct message", updatedAt: date(-1), is_sending_saving: false, + drafts_version: 1, }; const stream_draft_2 = { topic: "topic", @@ -647,6 +659,7 @@ test("filter_drafts", ({override, override_rewire, mock_template}) => { content: "Test stream message 2", updatedAt: date(-10), is_sending_saving: false, + drafts_version: 1, }; const pm_draft_2 = { private_message_recipient: "aaron@zulip.com", @@ -655,6 +668,7 @@ test("filter_drafts", ({override, override_rewire, mock_template}) => { content: "Test direct message 2", updatedAt: date(-5), is_sending_saving: false, + drafts_version: 1, }; const pm_draft_3 = { private_message_recipient: "aaron@zulip.com", @@ -663,6 +677,7 @@ test("filter_drafts", ({override, override_rewire, mock_template}) => { content: "Test direct message 3", updatedAt: date(-2), is_sending_saving: false, + drafts_version: 1, }; const expected_pm_drafts = [