-
-
Notifications
You must be signed in to change notification settings - Fork 670
Add stream_id to Outbox values #5000
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
Changes from all commits
e2ddb9b
1299518
ce2a0fa
6e99c7b
a040a2b
87ee111
0c251bf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ import type { LayoutEvent } from 'react-native/Libraries/Types/CoreEventTypes'; | |
import TextInputReset from 'react-native-text-input-reset'; | ||
import { type EdgeInsets } from 'react-native-safe-area-context'; | ||
import { compose } from 'redux'; | ||
import invariant from 'invariant'; | ||
|
||
import { withSafeAreaInsets } from '../react-native-safe-area-context'; | ||
import type { ThemeData } from '../styles'; | ||
|
@@ -31,6 +32,7 @@ import { FloatingActionButton, Input } from '../common'; | |
import { showToast } from '../utils/info'; | ||
import { IconDone, IconSend } from '../common/Icons'; | ||
import { | ||
isConversationNarrow, | ||
isStreamNarrow, | ||
isStreamOrTopicNarrow, | ||
isTopicNarrow, | ||
|
@@ -43,7 +45,6 @@ import getComposeInputPlaceholder from './getComposeInputPlaceholder'; | |
import NotSubscribed from '../message/NotSubscribed'; | ||
import AnnouncementOnly from '../message/AnnouncementOnly'; | ||
import MentionWarnings from './MentionWarnings'; | ||
|
||
import { getAuth, getIsAdmin, getStreamInNarrow, getVideoChatProvider } from '../selectors'; | ||
import { | ||
getIsActiveStreamSubscribed, | ||
|
@@ -66,9 +67,12 @@ type SelectorProps = {| | |
|}; | ||
|
||
type OuterProps = $ReadOnly<{| | ||
/** The narrow shown in the message list. Must be a conversation or stream. */ | ||
// In particular `getDestinationNarrow` makes assumptions about the narrow | ||
// (and other code might too.) | ||
narrow: Narrow, | ||
|
||
onSend: (string, Narrow) => void, | ||
onSend: (message: string, destinationNarrow: Narrow) => void, | ||
|
||
isEditing: boolean, | ||
|
||
|
@@ -391,23 +395,24 @@ class ComposeBoxInner extends PureComponent<Props, State> { | |
const topic = this.state.topic.trim(); | ||
return topicNarrow(streamName, topic || '(no topic)'); | ||
} | ||
invariant(isConversationNarrow(narrow), 'destination narrow must be conversation'); | ||
return narrow; | ||
}; | ||
|
||
handleSend = () => { | ||
const { dispatch } = this.props; | ||
const { message } = this.state; | ||
const narrow = this.getDestinationNarrow(); | ||
const destinationNarrow = this.getDestinationNarrow(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd be happy see this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The thing about that is that it'd mean we have two different state properties That certainly can be done, but it's something that can easily acquire subtle bugs. So I'd keep the function until we have a good reason to avoid it. In a future where we determine the destination narrow in some other way, the function also keeps it flexible for us to change that: its callsites just keep calling it. It might in the future refer to some other piece of state (like a current message, with the idea in your main comment above), or to a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I agree that this would get tricky. But when the user is composing a PM, in some sense it's a bug that Thinking some more about this, it occurs to me that // (if these end up lingering in `ComposeBox` and not split off to new child components)
const [ topic, setTopic ] = useState(/* ... */);
const [ pmRecipients, setPmRecipients ] = useState(/* ... */);
const destinationNarrow = /* ... */;
// Then it's very easy to react to changes in `destinationNarrow` in a
// `useEffect`, e.g., to send typing-stop and typing-start notifications as
// the destination narrow changes So I think after all we don't have a strong need to make a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah. Another angle is to say that for any future where we change what's in the state, if that makes something like |
||
|
||
this.props.onSend(message, narrow); | ||
this.props.onSend(message, destinationNarrow); | ||
|
||
this.setMessageInputValue(''); | ||
|
||
if (this.mentionWarnings.current) { | ||
this.mentionWarnings.current.clearMentionWarnings(); | ||
} | ||
|
||
dispatch(sendTypingStop(narrow)); | ||
dispatch(sendTypingStop(destinationNarrow)); | ||
}; | ||
|
||
inputMarginPadding = { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
/* @flow strict-local */ | ||
// $FlowFixMe[untyped-import] | ||
import parseMarkdown from 'zulip-markdown-parser'; | ||
import invariant from 'invariant'; | ||
|
||
import * as logging from '../utils/logging'; | ||
import type { | ||
|
@@ -11,6 +12,7 @@ import type { | |
Outbox, | ||
PmOutbox, | ||
StreamOutbox, | ||
Stream, | ||
UserOrBot, | ||
UserId, | ||
Action, | ||
|
@@ -23,11 +25,11 @@ import { | |
DELETE_OUTBOX_MESSAGE, | ||
MESSAGE_SEND_COMPLETE, | ||
} from '../actionConstants'; | ||
import { getAuth } from '../selectors'; | ||
import { getAuth, getStreamsByName } from '../selectors'; | ||
import * as api from '../api'; | ||
import { getAllUsersById, getOwnUser } from '../users/userSelectors'; | ||
import { getUsersAndWildcards } from '../users/userHelpers'; | ||
import { caseNarrowPartial } from '../utils/narrow'; | ||
import { caseNarrowPartial, isConversationNarrow } from '../utils/narrow'; | ||
import { BackoffMachine } from '../utils/async'; | ||
import { recipientsOfPrivateMessage, streamNameOfStreamMessage } from '../utils/recipient'; | ||
|
||
|
@@ -126,31 +128,34 @@ const recipientsFromIds = (ids, allUsersById, ownUser) => { | |
return result; | ||
}; | ||
|
||
// prettier-ignore | ||
type DataFromNarrow = | ||
| SubsetProperties<PmOutbox, {| type: mixed, display_recipient: mixed, subject: mixed |}> | ||
| SubsetProperties<StreamOutbox, {| type: mixed, display_recipient: mixed, subject: mixed |}>; | ||
| SubsetProperties<StreamOutbox, {| type: mixed, stream_id: mixed, display_recipient: mixed, subject: mixed |}>; | ||
|
||
const extractTypeToAndSubjectFromNarrow = ( | ||
narrow: Narrow, | ||
const outboxPropertiesForNarrow = ( | ||
destinationNarrow: Narrow, | ||
streamsByName: Map<string, Stream>, | ||
allUsersById: Map<UserId, UserOrBot>, | ||
ownUser: UserOrBot, | ||
): DataFromNarrow => | ||
caseNarrowPartial(narrow, { | ||
caseNarrowPartial(destinationNarrow, { | ||
pm: ids => ({ | ||
type: 'private', | ||
display_recipient: recipientsFromIds(ids, allUsersById, ownUser), | ||
subject: '', | ||
}), | ||
|
||
// TODO: we shouldn't ever be passing a whole-stream narrow here; | ||
// ensure we don't, then remove this case | ||
stream: name => ({ type: 'stream', display_recipient: name, subject: '(no topic)' }), | ||
|
||
topic: (streamName, topic) => ({ | ||
type: 'stream', | ||
display_recipient: streamName, | ||
subject: topic, | ||
}), | ||
topic: (streamName, topic) => { | ||
const stream = streamsByName.get(streamName); | ||
invariant(stream, 'narrow must be known stream'); | ||
return { | ||
type: 'stream', | ||
stream_id: stream.stream_id, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for doing this! Sorry I missed it in #4667. 🙂 |
||
display_recipient: stream.name, | ||
subject: topic, | ||
}; | ||
}, | ||
}); | ||
|
||
const getContentPreview = (content: string, state: GlobalState): string => { | ||
|
@@ -168,18 +173,24 @@ const getContentPreview = (content: string, state: GlobalState): string => { | |
} | ||
}; | ||
|
||
export const addToOutbox = (narrow: Narrow, content: string): ThunkAction<Promise<void>> => async ( | ||
dispatch, | ||
getState, | ||
) => { | ||
export const addToOutbox = ( | ||
destinationNarrow: Narrow, | ||
content: string, | ||
): ThunkAction<Promise<void>> => async (dispatch, getState) => { | ||
invariant(isConversationNarrow(destinationNarrow), 'destination narrow must be conversation'); | ||
const state = getState(); | ||
const ownUser = getOwnUser(state); | ||
|
||
const localTime = Math.round(new Date().getTime() / 1000); | ||
dispatch( | ||
messageSendStart({ | ||
isSent: false, | ||
...extractTypeToAndSubjectFromNarrow(narrow, getAllUsersById(state), ownUser), | ||
...outboxPropertiesForNarrow( | ||
destinationNarrow, | ||
getStreamsByName(state), | ||
getAllUsersById(state), | ||
ownUser, | ||
), | ||
markdownContent: content, | ||
content: getContentPreview(content, state), | ||
timestamp: localTime, | ||
|
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.
Commit-message nit:
It doesn't offer it when you're composing a new PM or editing one. Maybe one day it'll grow an input for PM recipients?
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.
Ah, the parenthetical was meant to be about the whole-stream case -- i.e. the case where this isn't a narrow you can actually send to. But that wasn't clear. I'll reword.