Skip to content
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

Remove redundant, stringly-typed fields from PmConversationData #4116

Closed

Conversation

rk-for-zulip
Copy link
Contributor

Replace the excessively quirky ids: string and recipients: string fields in PmConversationData with a users: Users[] field, unconditionally containing all participants.

Partly in support of #3764 and #4035. Blocks PR #4104 (although see below).

... but also to simplify further refactoring.
@rk-for-zulip rk-for-zulip requested a review from gnprice May 18, 2020 03:51
@rk-for-zulip
Copy link
Contributor Author

rk-for-zulip commented May 18, 2020

Somewhere around my 3.7th [sic] rebase-slash-rewrite of PR #4104, I got frustrated enough to do this first. This may not be the only way to keep the final version of that PR reasonable, but it's probably the best.

There is some overlap here with the commits in #4104: the commits for well-typing the relevant test code are taken from it. I believe I have addressed all of @gnprice's feedback for those commits in this version, with one notable exception (the NULL_OBJECT bit); I'll make a note of that as a "review" comment below. (In retrospect, I suppose these should have been split out into a separate PR.)

The final five commits (starting at recipient [nfc]: Generalize `filterRecipients`.) are somewhat speculative, and I shall be unsurprised if they provoke lengthy discussion. This is fine. It's certainly better that we merge the new logic in PmConversationList with the existing logic in recipient.js, but discussion on exactly how to go about doing that shouldn't block the preceding parts of the commit, and those are the parts that will unblock #4104.

Comment on lines +296 to +297
export const makeMessagesState = (messages: Message[]): MessagesState =>
objectFromEntries(messages.map(m => [m.id, m]));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feedback at #4104 (comment) resolved by a) stripping the exactness from both MessagesState itself (until Flow v0.111.0) and its indexer-property's value type, and b) eliminating the $FlowFixMe entirely.

Copy link
Member

@gnprice gnprice left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @ray-kraesig ! Happy to get these data structures cleaned up. Comments below about some of the specifics.

src/types.js Outdated
Comment on lines 335 to 340
/**
* A comma-separated sequence of the emails of the users involved in this
* conversation, sorted by user ID. Does not include the self-user, unless the
* self-user is the only recipient.
*/
recipients: string,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this true?

I don't think it is. See the implementation of normalizeRecipientsSansMe, and normalizeRecipients which it invokes. We sort there, by email address.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops! Will fix.

handleGroupNarrow = (email: string) => {
this.props.dispatch(doNarrow(groupNarrow(email.split(','))));
handleGroupNarrow = (users: UserOrBot[]) => {
this.props.dispatch(doNarrow(groupNarrow(users.map(s => s.email))));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The order here matters, because we use it for the key to look up the narrow in our data structures. So it's important to preserve the order used by the existing code, or else to carefully untangle to make it stop mattering.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, doesn't this now see the full set of users? Where previously it saw the set excluding self.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's odd – I specifically remember seeing that issue and fixing it. (The second one, not the first; the first is a carryover of my mistake in describing recipients.) Will fix again.

Comment on lines 45 to 56
/**
* If this is a 1:1 conversation, the other user involved. (For the
* self-conversation, this is the self-user.)
*
* If this is a group PM, null.
*/
getOtherUser = (users: UserOrBot[]): UserOrBot | null => {
const ownUserId = this.props.ownUser.user_id;
if (users.length <= 2) {
return users.filter(u => u.user_id !== ownUserId)[0];
}
return null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, does this work in the self-1:1 case? It looks like it'd end up returning [][0], which is undefined.

Comment on lines 39 to 46
handleGroupNarrow = (users: UserOrBot[]) => {
this.props.dispatch(doNarrow(groupNarrow(users.map(s => s.email))));
const { dispatch, ownUser } = this.props;
const emails = users.filter(u => u.user_id !== ownUser.user_id).map(u => u.email);
dispatch(doNarrow(groupNarrow(emails)));
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see. This change belongs in the earlier commit where we changed what set of users gets passed here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

– oh, there it is. I must have squashed the fix into the wrong commit. 😓

const unreadCards: Array<Card> = [
{
key: 'private',
data: [{ conversations, ...restProps }],
data: [conversations],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, can this really work with how this data gets used below?

          section.key === 'private' ? (
            <PmConversationList {...item} />

How does it know to call the prop conversations?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can't possibly have worked. I think when I tested it last night I wasn't actually running the right version of the code. 😓

|};
// This type cannot be made exact until Flow v0.111.0.
export type MessagesState = {
[id: number]: Message,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of removing exactness here, why not add it on Message itself? (And remove the then-redundant mention of it here.)

Otherwise we're regressing on how tightly we type-check.

For a quick experiment I made Message exact. Flow reported only one error -- and in fact it looks like a real one, which would have been caught in 3dc2d8f if we'd had Message exact then.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Message really isn't exact, though: it's full of unlisted fields from (possibly future versions of) the server. We shouldn't make the claim that it is. (The bug you cite is a good argument that eg.streamMessage and friends should take $Exact<Message>, though.)

I assume what we really want to do is to deconstruct the inexact, server-supplied ApiMessage object (to coin a name) into a fresh LocalMessage object that really is exact. But not, I think, today.

(I'm pretty sure this has come up before. I know I've documented it in Message at some point, but I suppose that hasn't made it into a PR yet. I'll try to dig it up and submit it separately. Or just rewrite it.)

@gnprice
Copy link
Member

gnprice commented May 19, 2020

The final five commits (starting at recipient [nfc]: Generalize `filterRecipients`.) are somewhat speculative, and I shall be unsurprised if they provoke lengthy discussion. This is fine.

As I think you guessed, I am not a fan of these last few changes. 🙂 They make this code significantly more complex, and I don't see a corresponding gain.

... following a brief archaeological expedition.
MessagesState is exact; until Flow v0.111.0, this is not usefully
compatible with indexer properties. This exactness was added in
8370002, as part of a mechanical
transformation, before we were aware of this issue.

MessagesState also has `$Exact<Message>` as its indexer value type,
rather than simply `Message`. This is the only use of `$Exact<...>`
directly as the type of a value in our codebase; it was added in
commit 01003e6, a professedly
experimental commit, where it is the only such change among several
less interesting `{ ... }` → `{| ... |}` conversions.

Revert both. Add a note about the former and Flow v0.111.0, for
grep's sake.
Additionally, make their arguments exact, to raise errors on
unrecognized arguments.
... 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.)
PmConversationData has two distinct and terrible ways of passing down
the list of users. Add a third way (presumably less terrible), which
will replace both of them.
... instead of threading the relevant Redux state through its callers.

(Consequently, eliminate the now-unused additional plumbing.)
Add a new function to `recipient.js` which will substitute for
`normalizeRecipientsSansMe` in the private conversation UI.

The new function is no longer stringly-typed, but is not otherwise an
improvement. (Also, `normalize` is a terrible name for what any of
these do.)
Remove its dependence on the old stringly-typed fields.

The existing code has relied on the selector to munge the data for UI
presentation; this now becomes the responsibility of the UI component
itself. (The logic to do so is presently inline, but is expected to be
unified with existing related logic in `recipient.js` later.)
The key used here doesn't have to be anything in particular, so long
as it's consistent. We assemble a nonce-key not used elsewhere. (Or,
if it does happen to be used elsewhere, we don't care.)
For the purposes of eliminating all but the latest message per
conversation, one uniquely-identifying string-key is as good as
another.

Since we no longer need to send `recipients` downstream, we might as
well just use `ids` -- in which case there's no longer any need for
`normalizeRecipientsSansMe` here.
... and, following the previous commit, there are no more uses of
`normalizeRecipientsSansMe`. Eliminate it.

Convert its tests to be used by the function which has effectively
replaced it, instead.
@rk-for-zulip rk-for-zulip force-pushed the downstream-nonsense-first branch from 2758052 to f371f09 Compare May 20, 2020 21:38
@rk-for-zulip
Copy link
Contributor Author

rk-for-zulip commented May 20, 2020

The new version may be politely described as less ambitious. It may be less politely described as "just pushing the junk from one room into another room".

The semantic mess that is normalizeRecipientsSansMe is no longer in a place where it gets in the way of work on #3133, but it hasn't been eliminated – just moved, with a new coat of paint on it.

(But at least we're no longer passing two different stringly-typed values in.)

@gnprice
Copy link
Member

gnprice commented Dec 25, 2020

The main goals of this PR have been taken care of separately since then, with the PR series up to #4356.

I've just sent #4358 with (rebased versions of) the parts of this PR that I think are useful and still relevant, plus some related new changes. Closing this one.

@gnprice gnprice closed this Dec 25, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants