-
-
Notifications
You must be signed in to change notification settings - Fork 832
Conversation
This is needed for the IRC bridge to be able to do full membership list syncing without cluttering the message panel.
Can one of the admins verify this patch? |
Note to self: test for element-hq/element-web#2020 |
netsplits across midnight is not handled, and @richvdh suggested splitting the list in two
Now it's: 1 user joined and left >1 others joined and left
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.
generally this looks like some great stuff! a few comments though :)
@@ -20,6 +20,7 @@ var dis = require("../../dispatcher"); | |||
var sdk = require('../../index'); | |||
|
|||
var MatrixClientPeg = require('../../MatrixClientPeg') | |||
var MemberEventListSummary = require('../views/elements/MemberEventListSummary.js'); |
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.
standard way to do this is with
const MemberEventListSummary = sdk.getComponent('views.elements.MemberEventListSummary');
in the relevant render function.
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.
@richvdh how does one make a component exist when using getComponent?
@@ -286,6 +287,47 @@ module.exports = React.createClass({ | |||
|
|||
var last = (i == lastShownEventIndex); | |||
|
|||
var isMembershipChange = (e) => |
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.
suggest hoisting this out of the for
loop so that it doesn't need to be redefined for each event
} | ||
summarisedEvents.push(collapsedMxEv); | ||
} | ||
let renderEvents = (pEvent, events) => { |
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.
let's have a comment here to say what we expect i
to be. Is it the last in the group, or the first that's not in the group?
<MemberEventListSummary | ||
events={summarisedEvents} | ||
previousEvent={prevEvent} | ||
renderEvents={renderEvents} |
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.
passing in a render
callback feels pretty icky here.
An alternative might be to hoist the event filtering logic in MemberEventListSummary.render
to here, then generate the tiles here, and then set them as children of the MemberEventListSummary
:
const filteredEvents = filterEvents(summarisedEvents); /* as per MemberEventListSummary.render() */
const tiles = filteredEvents.map( /* as above*/ );
<MemberEventListSummary events={summarisedEvents}>
{tiles}
</MemberEventListSummary>
and in MemberEventListSummary.render()
:
expandedEvents = this.props.children;
WDYT?
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.
I did have that thought. Yep, on reflection, WFM.
renderEvents={renderEvents} | ||
/> | ||
); | ||
prevEvent = mxEv; |
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.
don't you want the last event in the group, rather than the first?
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.
Yep, fair enough!
|
||
renderAvatars: function(events) { | ||
let avatars = events.slice(0, this.props.avatarsMaxLength).map((e) => { | ||
let onClickAvatar = () => { |
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.
I'd be sorely tempted to push this down into MemberAvatar, maybe with a viewUserOnClick=true
property, as a way to factor out the common code with MessagePanel.
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.
Yep, WFM.
render: function() { | ||
let summary = null; | ||
|
||
// Reorder events so that joins come before leaves |
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 above - suggest moving this logic to timelinepanel.
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.
How much are we talking? I can't move filteredEvents
on it's own because of the calculation for joinAndLeft
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.
oh, I think I misread before: I thought that the list being passed into renderEvents
depended on the filtering calculations. Looks like it doesn't, so this is fine.
toggleButton = ( | ||
<a onClick={this.toggleSummary} href="javascript:;">{expanded?'collapse':'expand'}</a> | ||
); | ||
let noun = (joinAndLeft === 1 ? 'user' : 'others'); |
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.
so... if 2 users join and leave, and nobody joins without leaving or vice versa... we'll just see "2 others joined and left"?
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.
Fair enough, I'll update that to be either 'others' or 'users' as appropriate.
if (!fewEvents) { | ||
summary = this.renderSummary(joinEvents, leaveEvents); | ||
toggleButton = ( | ||
<a onClick={this.toggleSummary} href="javascript:;">{expanded?'collapse':'expand'}</a> |
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.
don't think you need an href
here.
@@ -28,17 +28,29 @@ module.exports = React.createClass({ | |||
createOverflowElement: React.PropTypes.func | |||
}, | |||
|
|||
getInitialState: function() { |
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 looks unrelated... has it got lost?
I'm not quite sure what the intention is with it - it looks like what you are doing would be better handled by setting truncateAt = -1
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.
oops, didn't mean to commit this to the PR; I shall remove
@richvdh how does one make a component exist when using |
} | ||
summarisedEvents.push(collapsedMxEv); | ||
} | ||
// At this point, i = this.props.events.length OR i = the index of the first event |
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.
are you sure? line 303 suggests otherwise
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 yes, good shout!
).reduce((a,b) => a.concat(b)); | ||
}; | ||
|
||
let eventTiles = renderEvents(prevEvent, summarisedEvents); |
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.
inline renderEvents?
resizeMethod: React.PropTypes.string | ||
resizeMethod: React.PropTypes.string, | ||
// Whether the onClick of the avatar should dispatch 'view_user' | ||
viewUserOnClick: React.PropTypes.boolean |
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.
nit: trailing comma would be nice
}, | ||
|
||
getDefaultProps: function() { | ||
return { | ||
width: 40, | ||
height: 40, | ||
resizeMethod: 'crop' | ||
resizeMethod: 'crop', | ||
viewUserOnClick: false |
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.
ditto
@@ -65,9 +69,19 @@ module.exports = React.createClass({ | |||
|
|||
var {member, ...otherProps} = this.props; | |||
|
|||
var onClick = null; |
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.
some uses of MemberAvatar set props.onClick
to other things; you'll need to pass that down as the default, and probably exclude it from otherProps
above.
render: function() { | ||
let summary = null; | ||
|
||
// Reorder events so that joins come before leaves |
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.
oh, I think I misread before: I thought that the list being passed into renderEvents
depended on the filtering calculations. Looks like it doesn't, so this is fine.
|
||
// Special case the last name. ' and ' might be included later | ||
// So you have two cases: | ||
if (originalNumber <= this.props.summaryLength) { |
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 is a bit tortuous now. How about:
let lastName = this._getEventSenderName(lastEvent);
if (names.length === 0) {
// special-case for a single event
return lastName;
}
let remaining = originalNumber - this.props.summaryLength;
if (remaining > 0) {
// name1, name2, name3 and 100 others
return names + ', ' + lastName + ', and ' + remaining + ' others';
} else {
// name1, name2 and name3
return names + ' and ' + lastName;
}
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.
WFM!
matrixbot: ok to test |
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.
lgtm otherwise
// name1, name2, name3 [and 100 others] | ||
names += ', '; | ||
let lastName = this._getEventSenderName(lastEvent); | ||
if (names.length === 0) { |
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 makes lines 74-76 redundant
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.
oh yeah!
lgtm! |
This is needed for the IRC bridge to be able to do full membership list syncing (with quit/netsplit debouncing) without cluttering the message panel.
(See element-hq/element-web#349)
Also, for CSS changes, see element-hq/element-web#2565