@@ -33,15 +33,15 @@ export const doNarrow =
33
33
} ;
34
34
35
35
/**
36
- * Narrow to a /near/ link, possibly after reinterpreting it for a message move .
36
+ * Adjust a /near/ link as needed to account for message moves .
37
37
*
38
38
* It feels quite broken when a link is clearly meant to get you to a
39
39
* specific message, but tapping it brings you to a narrow where the message
40
40
* *used* to be but isn't anymore because it was moved to a new stream or
41
41
* topic. This was #5306.
42
42
*
43
43
* This action, when it can, recognizes when that's about to happen and
44
- * instead narrows you to the message's current stream/topic.
44
+ * instead finds the narrow for the message's current stream/topic.
45
45
*
46
46
* To do so, it obviously needs to know the message's current stream/topic.
47
47
* If those can't be gotten from Redux, we ask the server. If the server
@@ -51,8 +51,8 @@ export const doNarrow =
51
51
* N.B.: Gives a bad experience when the request takes a long time. We
52
52
* should fix that; see TODOs.
53
53
*/
54
- const doNarrowNearLink =
55
- ( narrow : Narrow , nearOperand : number ) : ThunkAction < Promise < void >> =>
54
+ const adjustNarrowForMoves =
55
+ ( narrow : Narrow , nearOperand : number ) : ThunkAction < Promise < Narrow >> =>
56
56
async ( dispatch , getState ) => {
57
57
const state = getState ( ) ;
58
58
@@ -61,46 +61,40 @@ const doNarrowNearLink =
61
61
const zulipFeatureLevel = getZulipFeatureLevel ( state ) ;
62
62
const allowEditHistory = getRealm ( state ) . allowEditHistory ;
63
63
64
- /**
65
- * Narrow to the /near/ link without reinterpreting it for a message move.
66
- *
67
- * Use this when the link is meant to find the specific message
68
- * identified by nearOperand, and:
69
- * - nearOperand refers to a message that wasn't moved outside the
70
- * narrow specified by the link, or
71
- * - nearOperand *might* refer to a message that was moved, but we don't
72
- * know; we've tried and failed to find out.
73
- *
74
- * Or, use this to insist on the traditional meaning of "near" before
75
- * the message-move feature: take the narrow's stream/topic/etc.
76
- * literally, and open to the message "nearest" the given ID (sent
77
- * around the same time), even if the message with that ID isn't
78
- * actually in the narrow [1].
79
- *
80
- * User docs on moving messages:
81
- * https://zulip.com/help/move-content-to-another-stream
82
- * https://zulip.com/help/move-content-to-another-topic
83
- *
84
- * [1] Tim points out, at
85
- * https://chat.zulip.org/#narrow/stream/101-design/topic/redirects.20from.20near.20links/near/1343095 :
86
- * "[…] useful for situations where you might replace an existing
87
- * search for `stream: 1/topic: 1/near: 15` with
88
- * `stream: 2/topic: 2/near: 15` in order to view what was happening
89
- * in another conversation at the same time as an existing
90
- * conversation."
91
- */
92
- const noMove = ( ) => {
93
- dispatch ( doNarrow ( narrow , nearOperand ) ) ;
94
- } ;
64
+ // Many control-flow paths here simply return the original narrow.
65
+ //
66
+ // We do this when the link is meant to find the specific message
67
+ // identified by nearOperand, and:
68
+ // - nearOperand refers to a message that wasn't moved outside the
69
+ // narrow specified by the link, or
70
+ // - nearOperand *might* refer to a message that was moved, but we don't
71
+ // know; we've tried and failed to find out.
72
+ //
73
+ // We also do this to insist on the traditional meaning of "near" before
74
+ // the message-move feature: take the narrow's stream/topic/etc.
75
+ // literally, and open to the message "nearest" the given ID (sent
76
+ // around the same time), even if the message with that ID isn't
77
+ // actually in the narrow [1].
78
+ //
79
+ // User docs on moving messages:
80
+ // https://zulip.com/help/move-content-to-another-stream
81
+ // https://zulip.com/help/move-content-to-another-topic
82
+ //
83
+ // [1] Tim points out, at
84
+ // https://chat.zulip.org/#narrow/stream/101-design/topic/redirects.20from.20near.20links/near/1343095 :
85
+ // "[…] useful for situations where you might replace an existing
86
+ // search for `stream: 1/topic: 1/near: 15` with
87
+ // `stream: 2/topic: 2/near: 15` in order to view what was happening
88
+ // in another conversation at the same time as an existing
89
+ // conversation."
95
90
96
91
const streamIdOperand =
97
92
isStreamNarrow ( narrow ) || isTopicNarrow ( narrow ) ? streamIdOfNarrow ( narrow ) : null ;
98
93
const topicOperand = isTopicNarrow ( narrow ) ? topicOfNarrow ( narrow ) : null ;
99
94
100
95
if ( streamIdOperand === null && topicOperand === null ) {
101
96
// Message moves only happen by changing the stream and/or topic.
102
- noMove ( ) ;
103
- return ;
97
+ return narrow ;
104
98
}
105
99
106
100
// Grab the message and see if it was moved, so we can follow the move
@@ -122,8 +116,7 @@ const doNarrowNearLink =
122
116
if ( zulipFeatureLevel < 120 ) {
123
117
// api.getSingleMessage won't give us the message's stream and
124
118
// topic; see there. Hopefully the message wasn't moved.
125
- noMove ( ) ;
126
- return ;
119
+ return narrow ;
127
120
}
128
121
try {
129
122
message = await api . getSingleMessage (
@@ -134,8 +127,7 @@ const doNarrowNearLink =
134
127
) ;
135
128
} catch {
136
129
// Hopefully the message, if it exists or ever existed, wasn't moved.
137
- noMove ( ) ;
138
- return ;
130
+ return narrow ;
139
131
}
140
132
}
141
133
@@ -144,23 +136,20 @@ const doNarrowNearLink =
144
136
// TODO(server-5.0): Simplify away.
145
137
if ( ! message ) {
146
138
logging . error ( '`message` from api.getSingleMessage unexpectedly falsy' ) ;
147
- noMove ( ) ;
148
- return ;
139
+ return narrow ;
149
140
}
150
141
151
142
if ( message . type === 'private' ) {
152
143
// A PM could never have been moved.
153
- noMove ( ) ;
154
- return ;
144
+ return narrow ;
155
145
}
156
146
157
147
if (
158
148
( topicOperand === null || topicOperand === message . subject )
159
149
&& ( streamIdOperand === null || streamIdOperand === message . stream_id )
160
150
) {
161
151
// The message is still in the stream and/or topic in the link.
162
- noMove ( ) ;
163
- return ;
152
+ return narrow ;
164
153
}
165
154
166
155
if (
@@ -169,10 +158,9 @@ const doNarrowNearLink =
169
158
) {
170
159
// The message was never in the narrow specified by the link. That'd
171
160
// be an odd link to put in a message…anyway, perhaps we're meant to
172
- // use the traditional meaning of "near"; see noMove's jsdoc
173
- // for what that is.
174
- noMove ( ) ;
175
- return ;
161
+ // use the traditional meaning of "near"; see large block comment at
162
+ // top of function.
163
+ return narrow ;
176
164
}
177
165
// If we couldn't access the edit history in the checks above, assume
178
166
// the message was moved. It's the likeliest explanation why its topic
@@ -182,21 +170,31 @@ const doNarrowNearLink =
182
170
183
171
// Reinterpret the link's narrow with the message's current stream
184
172
// and/or topic.
185
- dispatch (
186
- doNarrow (
187
- caseNarrowDefault (
188
- narrow ,
189
- {
190
- stream : ( ) => streamNarrow ( stream_id ) ,
191
- topic : ( ) => topicNarrow ( stream_id , subject ) ,
192
- } ,
193
- ( ) => narrow ,
194
- ) ,
195
- nearOperand ,
196
- ) ,
173
+ return caseNarrowDefault (
174
+ narrow ,
175
+ {
176
+ stream : ( ) => streamNarrow ( stream_id ) ,
177
+ topic : ( ) => topicNarrow ( stream_id , subject ) ,
178
+ } ,
179
+ ( ) => narrow ,
197
180
) ;
198
181
} ;
199
182
183
+ /**
184
+ * Narrow to a /near/ link, possibly after reinterpreting it for a message move.
185
+ *
186
+ * See `adjustNarrowForMoves` for more discussion.
187
+ *
188
+ * N.B.: Gives a bad experience when the request takes a long time. We
189
+ * should fix that; see `adjustNarrowForMoves`.
190
+ */
191
+ const doNarrowNearLink =
192
+ ( narrow : Narrow , nearOperand : number ) : ThunkAction < Promise < void >> =>
193
+ async ( dispatch , getState ) => {
194
+ const adjustedNarrow = await dispatch ( adjustNarrowForMoves ( narrow , nearOperand ) ) ;
195
+ dispatch ( doNarrow ( adjustedNarrow , nearOperand ) ) ;
196
+ } ;
197
+
200
198
export const messageLinkPress =
201
199
( href : string ) : ThunkAction < Promise < void >> =>
202
200
async ( dispatch , getState , { getGlobalSettings } ) => {
0 commit comments