mirror of
				https://github.com/zulip/zulip.git
				synced 2025-10-31 12:03:46 +00:00 
			
		
		
		
	narrow: Fix to show last message in narrow when narrow allows.
Fixes commit id 648a60baf6. When
allow_use_first_unread_when_narrowing() is false last message of
narrow is shown in view.
Comments rewritten by tabbott to explain in detail what's happening.
			
			
This commit is contained in:
		| @@ -325,7 +325,7 @@ run_test('search', () => { | ||||
|         }, | ||||
|         expected_id_info: { | ||||
|             target_id: undefined, | ||||
|             final_select_id: undefined, | ||||
|             final_select_id: 10000000000000000, | ||||
|             local_select_id: undefined, | ||||
|         }, | ||||
|         expected_msg_ids: [], | ||||
| @@ -387,6 +387,32 @@ run_test('stream, no unread, not in all_messages', () => { | ||||
|     test_with(fixture); | ||||
| }); | ||||
|  | ||||
| run_test('search, stream, not in all_messages', () => { | ||||
|     const fixture = { | ||||
|         filter_terms: [ | ||||
|             {operator: 'search', operand: 'foo'}, | ||||
|             {operator: 'stream', operand: 'whatever'}, | ||||
|         ], | ||||
|         unread_info: { | ||||
|             flavor: 'cannot_compute', | ||||
|         }, | ||||
|         has_found_newest: true, | ||||
|         empty: false, | ||||
|         all_messages: [ | ||||
|             {id: 400}, | ||||
|             {id: 500}, | ||||
|         ], | ||||
|         expected_id_info: { | ||||
|             target_id: undefined, | ||||
|             final_select_id: 10000000000000000, | ||||
|             local_select_id: undefined, | ||||
|         }, | ||||
|         expected_msg_ids: [], | ||||
|     }; | ||||
|  | ||||
|     test_with(fixture); | ||||
| }); | ||||
|  | ||||
| run_test('stream/topic not in all_messages', () => { | ||||
|     // This is a bit of a corner case, but you could have a scenario | ||||
|     // where you've gone way back in a topic (perhaps something that | ||||
|   | ||||
| @@ -219,15 +219,16 @@ exports.activate = function (raw_operators, opts) { | ||||
|         let anchor; | ||||
|         let use_first_unread; | ||||
|  | ||||
|         // Either we're trying to center the narrow around a | ||||
|         // particular message ID (which could be max_int), or we're | ||||
|         // asking the server to figure out for us what the first | ||||
|         // unread message is, and center the narrow around that. | ||||
|         if (id_info.final_select_id !== undefined) { | ||||
|             anchor = id_info.final_select_id; | ||||
|             use_first_unread = false; | ||||
|         } else if (narrow_state.filter().allow_use_first_unread_when_narrowing()) { | ||||
|         } else { | ||||
|             anchor = -1; | ||||
|             use_first_unread = true; | ||||
|         } else { | ||||
|             anchor = 10000000000000000; | ||||
|             use_first_unread = false; | ||||
|         } | ||||
|  | ||||
|         message_fetch.load_messages_for_narrow({ | ||||
| @@ -332,8 +333,22 @@ function load_local_messages(msg_data) { | ||||
| } | ||||
|  | ||||
| exports.maybe_add_local_messages = function (opts) { | ||||
|     // This function does two very closely related things, both of | ||||
|     // which are somewhat optional: | ||||
|     // This function determines whether we need to go to the server to | ||||
|     // fetch messages for the requested narrow, or whether we have the | ||||
|     // data cached locally to render the narrow correctly without | ||||
|     // waiting for the server.  There are two high-level outcomes: | ||||
|     // | ||||
|     // 1. We're centering this narrow on the first unread message: In | ||||
|     // this case final_select_id is left undefined or first unread | ||||
|     // message id locally. | ||||
|     // | ||||
|     // 2. We're centering this narrow on the most recent matching | ||||
|     // message. In this case we select final_select_id to the latest | ||||
|     // message in the local cache (if the local cache has the latest | ||||
|     // messages for this narrow) or max_int (if it doesn't). | ||||
|     // | ||||
|     // In either case, this function does two very closely related | ||||
|     // things, both of which are somewhat optional: | ||||
|     // | ||||
|     //  - update id_info with more complete values | ||||
|     //  - add messages into our message list from our local cache | ||||
| @@ -341,7 +356,29 @@ exports.maybe_add_local_messages = function (opts) { | ||||
|     const msg_data = opts.msg_data; | ||||
|     const unread_info = narrow_state.get_first_unread_info(); | ||||
|  | ||||
|     // If we don't have a specific message we're hoping to select | ||||
|     // (i.e. no `target_id`) and the narrow's filter doesn't | ||||
|     // allow_use_first_unread_when_narrowing, we want to just render | ||||
|     // the latest messages matching the filter.  To ensure this, we | ||||
|     // set an initial value final_select_id to `max_int`. | ||||
|     // | ||||
|     // While that's a confusing naming choice (`final_select_id` is | ||||
|     // meant to be final in the context of the caller), this sets the | ||||
|     // default behavior to be fetching and then selecting the very | ||||
|     // latest message in this narrow. | ||||
|     // | ||||
|     // If we're able to render the narrow locally, we'll end up | ||||
|     // overwriting this value with the ID of the latest message in the | ||||
|     // narrow later in this function. | ||||
|     if (!id_info.target_id && !narrow_state.filter().allow_use_first_unread_when_narrowing()) { | ||||
|         // Note that this may be overwritten; see above comment. | ||||
|         id_info.final_select_id = 10000000000000000; | ||||
|     } | ||||
|  | ||||
|     if (unread_info.flavor === 'cannot_compute') { | ||||
|         // Full-text search and potentially other future cases where | ||||
|         // we can't check which messages match on the frontend, so it | ||||
|         // doesn't matter what's in our cache, we must go to the server. | ||||
|         if (id_info.target_id) { | ||||
|             // TODO: Ideally, in this case we should be asking the | ||||
|             // server to give us the first unread or the target_id, | ||||
| @@ -357,11 +394,14 @@ exports.maybe_add_local_messages = function (opts) { | ||||
|     // We can now assume narrow_state.filter().can_apply_locally(), | ||||
|     // because !can_apply_locally => cannot_compute | ||||
|  | ||||
|     if (unread_info.flavor === 'found') { | ||||
|         // We have at least one unread message in this narrow.  So | ||||
|         // either we aim for the first unread message, or the | ||||
|         // target_id (if any), whichever is earlier.  See #2091 for a | ||||
|         // detailed explanation of why we need to look at unread here. | ||||
|     if (unread_info.flavor === 'found' && | ||||
|             narrow_state.filter().allow_use_first_unread_when_narrowing()) { | ||||
|         // We have at least one unread message in this narrow, and the | ||||
|         // narrow is one where we use the first unread message in | ||||
|         // narrowing positioning decisions.  So either we aim for the | ||||
|         // first unread message, or the target_id (if any), whichever | ||||
|         // is earlier.  See #2091 for a detailed explanation of why we | ||||
|         // need to look at unread here. | ||||
|         id_info.final_select_id = min_defined( | ||||
|             id_info.target_id, | ||||
|             unread_info.msg_id | ||||
| @@ -382,16 +422,17 @@ exports.maybe_add_local_messages = function (opts) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     // Now we know that there are no unread messages, because | ||||
|     //   unread_info.flavor === 'not_found' | ||||
|     // In all cases below here, the first unread message is irrelevant | ||||
|     // to our positioning decisions, either because there are no | ||||
|     // unread messages (unread_info.flavor === 'not_found') or because | ||||
|     // this is a mixed narrow where we prefer the bottom of the feed | ||||
|     // to the first unread message for positioning (and the narrow | ||||
|     // will be configured to not mark messages as read). | ||||
|  | ||||
|     if (!id_info.target_id) { | ||||
|         // Without unread messages or a target ID, we're narrowing to | ||||
|         // the very latest message matching the narrow. | ||||
|         // the very latest message or first unread if matching the narrow allows. | ||||
|  | ||||
|         // TODO: A possible optimization in this code path is to set | ||||
|         // `id_info.final_select_id` to be `max_int` here, i.e. saving the | ||||
|         // server the first_unread query when we need the server. | ||||
|         if (!message_list.all.fetch_status.has_found_newest()) { | ||||
|             // If message_list.all is not caught up, then we cannot | ||||
|             // populate the latest messages for the target narrow | ||||
| @@ -405,6 +446,7 @@ exports.maybe_add_local_messages = function (opts) { | ||||
|         // is caught up, so the last message in our now-populated | ||||
|         // msg_data object must be the last message matching the | ||||
|         // narrow the server could give us, so we can render locally. | ||||
|         // and use local latest message id instead of max_int if set earlier. | ||||
|         const last_msg = msg_data.last(); | ||||
|         id_info.final_select_id = last_msg.id; | ||||
|         id_info.local_select_id = id_info.final_select_id; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user