Merge pull request #473 from matrix-org/wmwragg/multi-invite-bugfix

Wmwragg/multi invite bugfix
This commit is contained in:
Matthew Hodgson 2016-09-14 22:06:28 +01:00 committed by GitHub
commit 1a126fee54
4 changed files with 82 additions and 49 deletions

View file

@ -71,10 +71,21 @@ module.exports = React.createClass({
}, },
onButtonClick: function() { onButtonClick: function() {
if (this.state.inviteList.length > 0) { var inviteList = this.state.inviteList.slice();
if (this._isDmChat()) { // Check the text input field to see if user has an unconverted address
// If there is and it's valid add it to the local inviteList
var check = Invite.isValidAddress(this.refs.textinput.value);
if (check === true || check === null) {
inviteList.push(this.refs.textinput.value);
} else if (this.refs.textinput.value.length > 0) {
this.setState({ error: true });
return;
}
if (inviteList.length > 0) {
if (this._isDmChat(inviteList)) {
// Direct Message chat // Direct Message chat
var room = this._getDirectMessageRoom(this.state.inviteList[0]); var room = this._getDirectMessageRoom(inviteList[0]);
if (room) { if (room) {
// A Direct Message room already exists for this user and you // A Direct Message room already exists for this user and you
// so go straight to that room // so go straight to that room
@ -82,13 +93,13 @@ module.exports = React.createClass({
action: 'view_room', action: 'view_room',
room_id: room.roomId, room_id: room.roomId,
}); });
this.props.onFinished(true, this.state.inviteList[0]); this.props.onFinished(true, inviteList[0]);
} else { } else {
this._startChat(this.state.inviteList); this._startChat(inviteList);
} }
} else { } else {
// Multi invite chat // Multi invite chat
this._startChat(this.state.inviteList); this._startChat(inviteList);
} }
} else { } else {
// No addresses supplied // No addresses supplied
@ -108,16 +119,16 @@ module.exports = React.createClass({
} else if (e.keyCode === 38) { // up arrow } else if (e.keyCode === 38) { // up arrow
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
this.addressSelector.onKeyUpArrow(); this.addressSelector.onKeyU();
} else if (e.keyCode === 40) { // down arrow } else if (e.keyCode === 40) { // down arrow
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
this.addressSelector.onKeyDownArrow(); this.addressSelector.onKeyDown();
} else if (e.keyCode === 13) { // enter } else if (e.keyCode === 13 || (e.keyCode === 9 && this.state.queryList.length > 0)) { // enter or tab
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
this.addressSelector.onKeyReturn(); this.addressSelector.onKeySelect();
} else if (e.keyCode === 32 || e.keyCode === 188) { // space or comma } else if (e.keyCode === 32 || e.keyCode === 188 || e.keyCode === 9) { // space, comma or tab
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
var check = Invite.isValidAddress(this.refs.textinput.value); var check = Invite.isValidAddress(this.refs.textinput.value);
@ -200,17 +211,22 @@ module.exports = React.createClass({
_startChat: function(addrs) { _startChat: function(addrs) {
if (this.props.roomId) { if (this.props.roomId) {
// Invite new user to a room // Invite new user to a room
var self = this;
Invite.inviteMultipleToRoom(this.props.roomId, addrs) Invite.inviteMultipleToRoom(this.props.roomId, addrs)
.then(function(addrs) {
var room = MatrixClientPeg.get().getRoom(this.props.roomId);
return self._showAnyInviteErrors(addrs, room);
})
.catch(function(err) { .catch(function(err) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Failure to invite user", title: "Failure to invite",
description: err.toString() description: err.toString()
}); });
return null; return null;
}) })
.done(); .done();
} else if (this._isDmChat()) { } else if (this._isDmChat(addrs)) {
// Start the DM chat // Start the DM chat
createRoom({dmUserId: addrs[0]}) createRoom({dmUserId: addrs[0]})
.catch(function(err) { .catch(function(err) {
@ -225,13 +241,18 @@ module.exports = React.createClass({
} else { } else {
// Start multi user chat // Start multi user chat
var self = this; var self = this;
var room;
createRoom().then(function(roomId) { createRoom().then(function(roomId) {
room = MatrixClientPeg.get().getRoom(roomId);
return Invite.inviteMultipleToRoom(roomId, addrs); return Invite.inviteMultipleToRoom(roomId, addrs);
}) })
.then(function(addrs) {
return self._showAnyInviteErrors(addrs, room);
})
.catch(function(err) { .catch(function(err) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Failure to invite user", title: "Failure to invite",
description: err.toString() description: err.toString()
}); });
return null; return null;
@ -254,11 +275,16 @@ module.exports = React.createClass({
var uid = user.userId.toLowerCase(); var uid = user.userId.toLowerCase();
query = query.toLowerCase(); query = query.toLowerCase();
// dount match any that are already on the invite list // don't match any that are already on the invite list
if (this._isOnInviteList(uid)) { if (this._isOnInviteList(uid)) {
return false; return false;
} }
// ignore current user
if (uid === MatrixClientPeg.get().credentials.userId) {
return false;
}
// direct prefix matches // direct prefix matches
if (name.indexOf(query) === 0 || uid.indexOf(query) === 0) { if (name.indexOf(query) === 0 || uid.indexOf(query) === 0) {
return true; return true;
@ -288,14 +314,33 @@ module.exports = React.createClass({
return false; return false;
}, },
_isDmChat: function() { _isDmChat: function(addrs) {
if (this.state.inviteList.length === 1 && Invite.getAddressType(this.state.inviteList[0]) === "mx" && !this.props.roomId) { if (addrs.length === 1 && Invite.getAddressType(addrs[0]) === "mx" && !this.props.roomId) {
return true; return true;
} else { } else {
return false; return false;
} }
}, },
_showAnyInviteErrors: function(addrs, room) {
// Show user any errors
var errorList = [];
for (var addr in addrs) {
if (addrs.hasOwnProperty(addr) && addrs[addr] === "error") {
errorList.push(addr);
}
}
if (errorList.length > 0) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Failed to invite the following users to the " + room.name + " room:",
description: errorList.join(", "),
});
}
return addrs;
},
render: function() { render: function() {
var TintableSvg = sdk.getComponent("elements.TintableSvg"); var TintableSvg = sdk.getComponent("elements.TintableSvg");
var AddressSelector = sdk.getComponent("elements.AddressSelector"); var AddressSelector = sdk.getComponent("elements.AddressSelector");

View file

@ -55,7 +55,7 @@ module.exports = React.createClass({
} }
}, },
onKeyUpArrow: function() { onKeyUp: function() {
if (this.state.selected > 0) { if (this.state.selected > 0) {
this.setState({ this.setState({
selected: this.state.selected - 1, selected: this.state.selected - 1,
@ -64,7 +64,7 @@ module.exports = React.createClass({
} }
}, },
onKeyDownArrow: function() { onKeyDown: function() {
if (this.state.selected < this._maxSelected(this.props.addressList)) { if (this.state.selected < this._maxSelected(this.props.addressList)) {
this.setState({ this.setState({
selected: this.state.selected + 1, selected: this.state.selected + 1,
@ -73,7 +73,7 @@ module.exports = React.createClass({
} }
}, },
onKeyReturn: function() { onKeySelect: function() {
this.selectAddress(this.state.selected); this.selectAddress(this.state.selected);
}, },

View file

@ -90,7 +90,7 @@ module.exports = React.createClass({
var EntityTile = sdk.getComponent("rooms.EntityTile"); var EntityTile = sdk.getComponent("rooms.EntityTile");
var BaseAvatar = sdk.getComponent("avatars.BaseAvatar"); var BaseAvatar = sdk.getComponent("avatars.BaseAvatar");
var label = input; // var label = input;
// if (input[0] === "@") { // if (input[0] === "@") {
// label = input; // label = input;
// } // }
@ -98,16 +98,16 @@ module.exports = React.createClass({
// label = "Email: " + input; // label = "Email: " + input;
// } // }
this._emailEntity = new Entities.newEntity( // this._emailEntity = new Entities.newEntity(
<EntityTile key="dynamic_invite_tile" suppressOnHover={true} showInviteButton={true} // <EntityTile key="dynamic_invite_tile" suppressOnHover={true} showInviteButton={true}
avatarJsx={ <BaseAvatar name="@" width={36} height={36} /> } // avatarJsx={ <BaseAvatar name="@" width={36} height={36} /> }
className="mx_EntityTile_invitePlaceholder" // className="mx_EntityTile_invitePlaceholder"
presenceState="online" onClick={this.onThirdPartyInvite} name={"Invite by email"} // presenceState="online" onClick={this.onThirdPartyInvite} name={"Invite by email"}
/>, // />,
function(query) { // function(query) {
return true; // always show this // return true; // always show this
} // }
); // );
this.props.onSearchQueryChanged(input); this.props.onSearchQueryChanged(input);
}, },
@ -117,9 +117,9 @@ module.exports = React.createClass({
var entities = Entities.fromUsers(this._userList || [], true, this.props.onInvite); var entities = Entities.fromUsers(this._userList || [], true, this.props.onInvite);
// Add an "Email: foo@bar.com" tile as the first tile // Add an "Email: foo@bar.com" tile as the first tile
if (this._emailEntity) { // if (this._emailEntity) {
entities.unshift(this._emailEntity); // entities.unshift(this._emailEntity);
} // }
return ( return (
<SearchableEntityList searchPlaceholderText={"Search/invite by name, email, id"} <SearchableEntityList searchPlaceholderText={"Search/invite by name, email, id"}

View file

@ -102,7 +102,7 @@ var SearchableEntityList = React.createClass({
getSearchResults: function(query, entities) { getSearchResults: function(query, entities) {
if (!query || query.length === 0) { if (!query || query.length === 0) {
return this.props.emptyQueryShowsAll ? entities : [ entities[0] ] return this.props.emptyQueryShowsAll ? entities : [];
} }
return entities.filter(function(e) { return entities.filter(function(e) {
return e.matches(query); return e.matches(query);
@ -135,20 +135,8 @@ var SearchableEntityList = React.createClass({
<form onSubmit={this.onQuerySubmit} autoComplete="off"> <form onSubmit={this.onQuerySubmit} autoComplete="off">
<input className="mx_SearchableEntityList_query" id="mx_SearchableEntityList_query" type="text" <input className="mx_SearchableEntityList_query" id="mx_SearchableEntityList_query" type="text"
onChange={this.onQueryChanged} value={this.state.query} onChange={this.onQueryChanged} value={this.state.query}
onFocus={ ()=>{ onFocus= {() => { this.setState({ focused: true }) }}
if (this._blurTimeout) { onBlur= {() => { this.setState({ focused: false }) }}
clearTimeout(this.blurTimeout);
}
this.setState({ focused: true });
} }
onBlur={ ()=>{
// nasty setTimeout heuristic to avoid the 'invite by email' prompt disappearing
// due to the onBlur before we can click on it
this._blurTimeout = setTimeout(
()=>{ this.setState({ focused: false }) },
300
);
} }
placeholder={this.props.searchPlaceholderText} /> placeholder={this.props.searchPlaceholderText} />
</form> </form>
); );