diff --git a/src/chat/narrowsSelectors.js b/src/chat/narrowsSelectors.js index 2d13ce3e945..2f4a9c88929 100644 --- a/src/chat/narrowsSelectors.js +++ b/src/chat/narrowsSelectors.js @@ -26,7 +26,7 @@ import { isPrivateNarrow, isStreamOrTopicNarrow, emailsOfGroupNarrow, - narrowContains, + narrowContainsOutbox, } from '../utils/narrow'; import { shouldBeMuted } from '../utils/message'; import { NULL_ARRAY, NULL_SUBSCRIPTION } from '../nullObjects'; @@ -39,7 +39,7 @@ export const outboxMessagesForNarrow: Selector = createSelecto if (!caughtUp.newer) { return NULL_ARRAY; } - const filtered = outboxMessages.filter(item => narrowContains(narrow, item.narrow)); + const filtered = outboxMessages.filter(item => narrowContainsOutbox(narrow, item)); return isEqual(filtered, outboxMessages) ? outboxMessages : filtered; }, ); diff --git a/src/outbox/outboxActions.js b/src/outbox/outboxActions.js index 3112bea9c87..3c2332dcd7d 100644 --- a/src/outbox/outboxActions.js +++ b/src/outbox/outboxActions.js @@ -64,17 +64,16 @@ export const trySendMessages = (dispatch: Dispatch, getState: GetState): boolean return; // i.e., continue } - const to = ((): string => { - const { narrow } = item; - // TODO: can this test be `if (item.type === private)`? - if (isPrivateOrGroupNarrow(narrow)) { - return narrow[0].operand; - } else { - // HACK: the server attempts to interpret this argument as JSON, then - // CSV, then a literal. To avoid misparsing, always use JSON. - return JSON.stringify([item.display_recipient]); - } - })(); + // prettier-ignore + const to = + item.type === 'private' + // This will include the self user, possibly twice. That's + // fine; on send, the server (since at least 2013) drops dupes + // and normalizes whether to include the sender. + ? item.display_recipient.map(r => r.email).join(',') + // HACK: the server attempts to interpret this argument as JSON, then + // CSV, then a literal. To avoid misparsing, always use JSON. + : JSON.stringify([item.display_recipient]); await api.sendMessage(auth, { type: item.type, @@ -164,7 +163,6 @@ export const addToOutbox = (narrow: Narrow, content: string) => async ( const localTime = Math.round(new Date().getTime() / 1000); dispatch( messageSendStart({ - narrow, isSent: false, ...extractTypeToAndSubjectFromNarrow(narrow, getUsersByEmail(state), userDetail), markdownContent: content, diff --git a/src/types.js b/src/types.js index a5d7f362dc3..6ad9e2b893a 100644 --- a/src/types.js +++ b/src/types.js @@ -2,7 +2,7 @@ import type { IntlShape } from 'react-intl'; import type { DangerouslyImpreciseStyleProp } from 'react-native/Libraries/StyleSheet/StyleSheet'; -import type { Auth, Topic, Message, Reaction, ReactionType, Narrow } from './api/apiTypes'; +import type { Auth, Topic, Message, Reaction, ReactionType } from './api/apiTypes'; import type { ZulipVersion } from './utils/zulipVersion'; export type * from './generics'; @@ -171,10 +171,9 @@ export type Outbox = {| */ isSent: boolean, - // These fields don't exist in `Message`. - // They're used for sending the message to the server. + // `markdownContent` doesn't exist in `Message`. + // It's used for sending the message to the server. markdownContent: string, - narrow: Narrow, // These fields are modeled on `Message`. avatar_url: string | null, diff --git a/src/utils/logging.js b/src/utils/logging.js index a86868369e3..98849e503ed 100644 --- a/src/utils/logging.js +++ b/src/utils/logging.js @@ -124,14 +124,14 @@ const makeLogFunction = ({ consoleMethod, severity }: LogParams): LogFunction => * represents a bug. For conditions that can happen without a bug (e.g. a * failure to reach the server), consider `logging.warn`. * + * See also: + * * `logging.warn` for logging at lower severity + * * @param event A string describing the nature of the event to be logged, or an * exception whose `.message` is such a string. Related events should have * identical such strings, when feasible. * @param extras Diagnostic data which may differ between separate occurrences * of the event. - * - * See also: - * * `logging.warn` for logging at lower severity */ export const error: (event: string | Error, extras?: Extras) => void = makeLogFunction({ consoleMethod: console.error, @@ -148,14 +148,14 @@ export const error: (event: string | Error, extras?: Extras) => void = makeLogFu * which have an inevitable background rate. For conditions which * definitely represent a bug in the app, consider `logging.error` instead. * + * See also: + * * `logging.error` for logging at higher severity + * * @param event A string describing the nature of the event to be logged, or an * exception whose `.message` is such a string. Related events should have * identical such strings, when feasible. * @param extras Diagnostic data which may differ between separate occurrences * of the event. - * - * See also: - * * `logging.error` for logging at higher severity */ export const warn: (event: string | Error, extras?: Extras) => void = makeLogFunction({ consoleMethod: console.warn, diff --git a/src/utils/narrow.js b/src/utils/narrow.js index 0ea5e25c45c..ba6f8706438 100644 --- a/src/utils/narrow.js +++ b/src/utils/narrow.js @@ -248,19 +248,24 @@ export const canSendToNarrow = (narrow: Narrow): boolean => search: () => false, }); -/** True just if `haystack` contains all possible messages in `needle`. */ -export const narrowContains = (haystack: Narrow, needle: Narrow): boolean => { - if (isHomeNarrow(haystack)) { - return true; - } - if (isAllPrivateNarrow(haystack) && isPrivateOrGroupNarrow(needle)) { - return true; - } - if (isStreamNarrow(haystack) && needle[0].operand === haystack[0].operand) { - return true; - } - return JSON.stringify(needle) === JSON.stringify(haystack); -}; +export const narrowContainsOutbox = (haystack: Narrow, needle: Outbox): boolean => + caseNarrowPartial(haystack, { + stream: name => needle.type === 'stream' && needle.display_recipient === name, + topic: (streamName, topic) => + needle.type === 'stream' + && needle.display_recipient === streamName + && needle.subject === topic, + pm: emails => emails === needle.display_recipient.map(r => r.email).join(','), + + home: () => true, + allPrivate: () => needle.type === 'private', + starred: () => false, + + // These two are uncommon cases it'd take some work to get right; just + // leave the outbox messages out. + mentioned: () => false, + search: () => false, + }); export const getNarrowFromMessage = (message: Message | Outbox, ownEmail: string) => { if (Array.isArray(message.display_recipient)) {