-
-
Notifications
You must be signed in to change notification settings - Fork 657
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use recent_private_conversations on PMs screen, when available #4104
Conversation
Additionally, improve typing on user-creation functions, so that they no longer happily accept (and ignore) `id: 0`.
... an expansion of `pmMessage` allowing (and requiring) the caller to supply the users involved in the message.
... which assembles a `MessagesState` from the `Message`s that compose it.
Translate existing tests from JavaScript to Flow. (There is no significant functional difference, but there are some minor changes to irrelevant data under the hood.)
... in support of a reducer for new state, shortly to be added. (This is also in support of zulip#3764, although it takes no additional stpes towards it.)
The server added in zulip/zulip#11944 basic support for fetching the most recent private conversations that a user was involved in. The endpoint returns the private conversations a user has had within the past 1000 private messages they have sent/received. The endpoint returns data in the form of `[{user_ids, max_message_id}]` where user_ids lists all the people involved in the conversation, and max_message_id returns the message_id of the most recent message in the conversation. This commit adds only the minimum machinery necessary to request this data from the server at `register` time. [ray: Split original initial commit into two parts, this being the first. Minor changes to Flow types.]
This commit introduces the reducers required to introduce this data into the Redux state, during `doInitialFetch`. It only catches the `REALM_INIT` action at the moment, and the rest of the actions will be added in a later commit with details. It does not yet store the data received from the server in REALM_INIT. Some additional work will need to be done to convert the data received from older server versions. [ray: Split original commit into two parts, this being the second. Temporarily disabled REALM_INIT reducer, just in case.]
Code to sort the `user_id`s in `recent_private_conversations` was not added until 2.2-dev-53-g405a529340 (zulip/zulip@405a529340). This was backported to the 2.1 branch as 2.1.1-50-gd452ad31e0 (zulip/zulip@d452ad31e0). Since we can't easily access the current server version here (yet?), just unconditionally sort the data. This is sufficient for us to begin storing the server data.
Since the `PmConversationsCard` needs to be updated when a new message comes in and the data it uses to be updated is in `recentPrivateConversations` key in the Redux state, this event catch adds/amends the data in the state to correctly match the most recent private messages. A unit test file has been created for this use-case as well. It is `strict-local`, and uses `exampleData.js` for its data source. [ray: rewrote test file to use new functions; (bugfix) properly filtered ownId out of `display_recipient`.]
... but also to simplify further refactoring.
We're about to add an alternate implementation of this function, but we'll need to keep the existing version to avoid loss of functionality on pre-2.1 servers. Preemptively factor some fragments of the existing implementation out, as we'll need to use them in more and/or different places.
Add new implementation of `getRecentConversations`, based on new `recent_private_conversations` data. We can't get this data on pre-2.1 servers, so we continue using the legacy data there, to avoid a regression for users on such servers. (Without this, they would never see any old conversations in the PMs window; only those with messages that have come in during the current session would be visible.) In upcoming commits: * New tests for the new implementation (alongside the retained tests for the legacy implementation). * Adjusting the main selector to be more efficient, rather than potentially computing both the modern and legacy implementations on every call. Based in part on work by Isham Mahajan <[email protected]>.
Based closely on the tests for the old implementation. Taken with minimal changes from PR zulip#3535. Co-authored-by: Greg Price <[email protected]> [ray: ported from old PR; wrote new commit message for new context.]
Bind up the decision of whether to use the old or new implementation into a selector of its own. This simultaneously caches that decision and ensures that only the necessary implementation, and not its complement, is ever invoked.
Suggested future work:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @ray-kraesig ! Glad to see this moving forward. See comments below.
I am concerned about the quantity of new code this adds in pmConversationsSelectors.js
. There's going to be a net increase because we don't get to remove the legacy implementation; but this takes it from 61 lines to 181 lines, which is a lot more than I'd expect, and the result does feel like a lot more to read through.
Several of the comments below have specific suggestions for reducing that. Please also look for ways you can simplify in general.
Remove the "nastiness" mentioned in the previous PR's 5343872 – preferably not by pushing it into
recipient.js
, which has quite enough nastiness in it already, but instead by making the sole downstream consumer of this code accept a #3764-compliant data structure.
I just saw this on rereading your PR comment, and it relates to some comments I made below. I'm all for future changes to eliminate (cases of) this kind of complexity entirely. Until we do, it's important to be clear about what it's doing. Otherwise we're just creating new archeological and reverse-engineering problems for our future selves to solve -- which is the hardest part of the work to remove such things.
// exact object + indexer properties issue; fixed in v0.111.0 | ||
return (state: $FlowFixMe); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This catches my eye because MessagesState
may switch from an object-as-map to a Map or Immutable.Map soon, and I'd like to rely on the type-checker to find places we need to update.
When I remove the fixme, one thing I notice is there are actually two errors here -- and one of them isn't related to that Flow bug, I think, but comes from the fact that (a) Message
is an inexact type, but (b) MessagesState
uses $Exact<Message>
. That contrast seems odd and I don't recall why we have it.
I'd feel better if this were explicit about what kind of type difference it's meant to launder. If e.g. this line were to spell out what the MessagesState
type is -- which will look very similar to the type on state
just above, so the reader can compare to see what's being fudged -- then I think that'd do it. Then Flow would check that that type indeed can be used as MessagesState
, so when the latter changes incompatibly it'll give an error here.
* contain only the most recent message from any conversation, and return them | ||
* sorted by recency. | ||
*/ | ||
const collateByRecipient = <T: { recipients: string, msgId: number }>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this is only used in the one place? I don't think it's a win to pull it out -- the interface is pretty complicated in isolation.
const getAttachUnread: Selector<UnreadAttacher> = createSelector( | ||
getUnreadByPms, | ||
getUnreadByHuddles, | ||
(unreadPms: { [number]: number }, unreadHuddles: { [string]: number }) => ( | ||
partials: $ReadOnlyArray<PmConversationPartial>, | ||
) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's nothing to memoize here, because the body is just a lambda.
The logic inside that lambda -- certainly the expression after unread:
, complete with comments -- is indeed helpful to factor out into a helper function. That helper can take unreadPms
and unreadHuddles
among its arguments.
throw new Error('getRecentConversations: unknown user id'); | ||
}; | ||
|
||
const recipients = recentPCs.map(conversation => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As you astutely noted on the legacy implementation, there's probably a better name to give to this local 😉
const userIds = conversation.user_ids.slice(); | ||
if (userIds.length !== 1) { | ||
userIds.push(ownUser.user_id); | ||
userIds.sort((a, b) => a - b); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should also go in recipients.js
, with a name and jsdoc.
Specifically, a good name/interface might be:
- include the
.join(',')
part; - call it
pmUnreadsKeyFromRecentPmsKey
.
recipients: normalizeRecipientsSansMe( | ||
userIds.map(id => ({ email: getEmail(id) })), | ||
ownUser.email, | ||
), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oof. I think this ends up having the right behavior... but it sure is confusing from a #4035 perspective. Note that we're giving this function a different version of "the users for this PM conversation" than we do at its other call site. And that not all possible versions of that would work -- notably if we used conversation.user_ids
directly, that would not work.
At a minimum I'd want a comment here explaining why this ends up with the right set of users (and what the right set of users is supposed to be.)
Better would be another small function in recipients.js
with its own name and jsdoc.
A good followup would be to eliminate this recipients
property entirely. It flows to just a handful of places, all under our direct control.
I've just sent #4392 as a new approach to this issue. |
Attempt to acquire
recent_private_conversations
from the server (zulip/zulip#11946). Add a new implementation forgetRecentConversations
which will use the data provided therein.Since there are many Zulip servers still active which predate this server-side feature, we continue to use the old implementation when connecting to those servers, to avoid a significant regression.
This PR is intended to supersede PR #3535, with which it shares some code and history. Notable functional differences include:
exampleData
to ease test construction.EVENT_NEW_MESSAGE
reducer now properly filtersdisplay_recipient
. (Noticed while converting its tests to use the new functions.)Fixes #3133.