about summary refs log tree commit diff
diff options
context:
space:
mode:
authorClaire <claire.github-309c@sitedethib.com>2022-04-07 11:27:35 +0200
committerGitHub <noreply@github.com>2022-04-07 11:27:35 +0200
commit1b91359a4508b3068207ef4fd798a56549575591 (patch)
tree610ba32c92dbc9bd67d86e4f26c5cca4dcc8db36
parentf382192862893c48cf97f13e9fbfb85b80cdc97d (diff)
Fix older items possibly disappearing on timeline updates (#17980)
In some rare cases, when receiving statuses out of order from the streaming
API then polling from the REST API, it was possible for the
`expandNormalizedTimeline` function to remove older items from the timeline.

This commit ensures that any item from the replaced slice that is older
than the oldest item retrieved from the API gets added back to the replaced
slice.
-rw-r--r--app/javascript/mastodon/reducers/timelines.js15
1 files changed, 12 insertions, 3 deletions
diff --git a/app/javascript/mastodon/reducers/timelines.js b/app/javascript/mastodon/reducers/timelines.js
index 301997567..53a644e47 100644
--- a/app/javascript/mastodon/reducers/timelines.js
+++ b/app/javascript/mastodon/reducers/timelines.js
@@ -66,13 +66,22 @@ const expandNormalizedTimeline = (state, timeline, statuses, next, isPartial, is
 
         // Then, try to find the furthest (if properly sorted, oldest) item in the timeline that
         // is newer than the most recent fetched one, as it delimits a section comprised of only
-        // items present in `newIds` (or that were deleted from the server, so should be removed
+        // items older or within `newIds` (or that were deleted from the server, so should be removed
         // anyway).
         // Stop the gap *after* that item.
         const firstIndex = oldIds.take(lastIndex).findLastIndex(id => id !== null && compareId(id, newIds.first()) > 0) + 1;
 
-        // Make sure we aren't inserting duplicates
-        let insertedIds = ImmutableOrderedSet(newIds).subtract(oldIds.take(firstIndex), oldIds.skip(lastIndex)).toList();
+        let insertedIds = ImmutableOrderedSet(newIds).withMutations(insertedIds => {
+          // It is possible, though unlikely, that the slice we are replacing contains items older
+          // than the elements we got from the API. Get them and add them back at the back of the
+          // slice.
+          const olderIds = oldIds.slice(firstIndex, lastIndex).filter(id => id !== null && compareId(id, newIds.last()) < 0);
+          insertedIds.union(olderIds);
+
+          // Make sure we aren't inserting duplicates
+          insertedIds.subtract(oldIds.take(firstIndex), oldIds.skip(lastIndex));
+        }).toList();
+
         // Finally, insert a gap marker if the data is marked as partial by the server
         if (isPartial && (firstIndex === 0 || oldIds.get(firstIndex - 1) !== null)) {
           insertedIds = insertedIds.unshift(null);