Move DM creation logic into DMInviteDialog
Fixes https://github.com/vector-im/riot-web/issues/11645 The copy hasn't been reviewed by anyone and could probably use some work.
This commit is contained in:
parent
fa174512cc
commit
443744733d
5 changed files with 122 additions and 18 deletions
|
@ -67,6 +67,17 @@ limitations under the License.
|
||||||
height: 25px;
|
height: 25px;
|
||||||
line-height: 25px;
|
line-height: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_DMInviteDialog_buttonAndSpinner {
|
||||||
|
.mx_Spinner {
|
||||||
|
// Width and height are required to trick the layout engine.
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
margin-left: 5px;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_DMInviteDialog_section {
|
.mx_DMInviteDialog_section {
|
||||||
|
|
|
@ -36,21 +36,19 @@ import SettingsStore from "./settings/SettingsStore";
|
||||||
* @param {string[]} addrs Array of strings of addresses to invite. May be matrix IDs or 3pids.
|
* @param {string[]} addrs Array of strings of addresses to invite. May be matrix IDs or 3pids.
|
||||||
* @returns {Promise} Promise
|
* @returns {Promise} Promise
|
||||||
*/
|
*/
|
||||||
function inviteMultipleToRoom(roomId, addrs) {
|
export function inviteMultipleToRoom(roomId, addrs) {
|
||||||
const inviter = new MultiInviter(roomId);
|
const inviter = new MultiInviter(roomId);
|
||||||
return inviter.invite(addrs).then(states => Promise.resolve({states, inviter}));
|
return inviter.invite(addrs).then(states => Promise.resolve({states, inviter}));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function showStartChatInviteDialog() {
|
export function showStartChatInviteDialog() {
|
||||||
if (SettingsStore.isFeatureEnabled("feature_ftue_dms")) {
|
if (SettingsStore.isFeatureEnabled("feature_ftue_dms")) {
|
||||||
|
// This new dialog handles the room creation internally - we don't need to worry about it.
|
||||||
const DMInviteDialog = sdk.getComponent("dialogs.DMInviteDialog");
|
const DMInviteDialog = sdk.getComponent("dialogs.DMInviteDialog");
|
||||||
Modal.createTrackedDialog('Start DM', '', DMInviteDialog, {
|
Modal.createTrackedDialog(
|
||||||
onFinished: (inviteIds) => {
|
'Start DM', '', DMInviteDialog, {},
|
||||||
// TODO: Replace _onStartDmFinished with less hacks
|
/*className=*/null, /*isPriority=*/false, /*isStatic=*/true,
|
||||||
if (inviteIds.length > 0) _onStartDmFinished(true, inviteIds.map(i => ({address: i})));
|
);
|
||||||
// else ignore and just do nothing
|
|
||||||
},
|
|
||||||
}, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,8 @@ import {abbreviateUrl} from "../../../utils/UrlUtils";
|
||||||
import dis from "../../../dispatcher";
|
import dis from "../../../dispatcher";
|
||||||
import IdentityAuthClient from "../../../IdentityAuthClient";
|
import IdentityAuthClient from "../../../IdentityAuthClient";
|
||||||
import Modal from "../../../Modal";
|
import Modal from "../../../Modal";
|
||||||
|
import createRoom from "../../../createRoom";
|
||||||
|
import {inviteMultipleToRoom} from "../../../RoomInvite";
|
||||||
|
|
||||||
// TODO: [TravisR] Make this generic for all kinds of invites
|
// TODO: [TravisR] Make this generic for all kinds of invites
|
||||||
|
|
||||||
|
@ -295,6 +297,10 @@ export default class DMInviteDialog extends React.PureComponent {
|
||||||
threepidResultsMixin: [], // { user: ThreepidMember, userId: string}[], like recents and suggestions
|
threepidResultsMixin: [], // { user: ThreepidMember, userId: string}[], like recents and suggestions
|
||||||
canUseIdentityServer: !!MatrixClientPeg.get().getIdentityServerUrl(),
|
canUseIdentityServer: !!MatrixClientPeg.get().getIdentityServerUrl(),
|
||||||
tryingIdentityServer: false,
|
tryingIdentityServer: false,
|
||||||
|
|
||||||
|
// These two flags are used for the 'Go' button to communicate what is going on.
|
||||||
|
busy: true,
|
||||||
|
errorText: _t("We couldn't create your DM. Please check the users you want to invite and try again."),
|
||||||
};
|
};
|
||||||
|
|
||||||
this._editorRef = createRef();
|
this._editorRef = createRef();
|
||||||
|
@ -381,11 +387,66 @@ export default class DMInviteDialog extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
_startDm = () => {
|
_startDm = () => {
|
||||||
this.props.onFinished(this.state.targets.map(t => t.userId));
|
this.setState({busy: true});
|
||||||
|
const targetIds = this.state.targets.map(t => t.userId);
|
||||||
|
|
||||||
|
// Check if there is already a DM with these people and reuse it if possible.
|
||||||
|
const existingRoom = DMRoomMap.shared().getDMRoomForIdentifiers(targetIds);
|
||||||
|
if (existingRoom) {
|
||||||
|
dis.dispatch({
|
||||||
|
action: 'view_room',
|
||||||
|
room_id: existingRoom.roomId,
|
||||||
|
should_peek: false,
|
||||||
|
joining: false,
|
||||||
|
});
|
||||||
|
this.props.onFinished();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it's a traditional DM and create the room if required.
|
||||||
|
// TODO: [Canonical DMs] Remove this check and instead just create the multi-person DM
|
||||||
|
let createRoomPromise = Promise.resolve();
|
||||||
|
if (targetIds.length === 1) {
|
||||||
|
createRoomPromise = createRoom({dmUserId: targetIds[0]})
|
||||||
|
} else {
|
||||||
|
// Create a boring room and try to invite the targets manually.
|
||||||
|
let room;
|
||||||
|
createRoomPromise = createRoom().then(roomId => {
|
||||||
|
room = MatrixClientPeg.get().getRoom(roomId);
|
||||||
|
return inviteMultipleToRoom(roomId, targetIds);
|
||||||
|
}).then(result => {
|
||||||
|
const failedUsers = Object.keys(result.states).filter(a => result.states[a] === 'error');
|
||||||
|
if (failedUsers.length > 0) {
|
||||||
|
console.log("Failed to invite users: ", result);
|
||||||
|
this.setState({
|
||||||
|
busy: false,
|
||||||
|
errorText: _t("Failed to invite the following users to chat: %(csvUsers)s", {
|
||||||
|
csvUsers: failedUsers.join(", "),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
return true; // abort
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// the createRoom call will show the room for us, so we don't need to worry about that.
|
||||||
|
createRoomPromise.then(abort => {
|
||||||
|
if (abort === true) return; // only abort on true booleans, not roomIds or something
|
||||||
|
this.props.onFinished();
|
||||||
|
}).catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
this.setState({
|
||||||
|
busy: false,
|
||||||
|
errorText: _t("We couldn't create your DM. Please check the users you want to invite and try again."),
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
_cancel = () => {
|
_cancel = () => {
|
||||||
this.props.onFinished([]);
|
// We do not want the user to close the dialog while an action is in progress
|
||||||
|
if (this.state.busy) return;
|
||||||
|
|
||||||
|
this.props.onFinished();
|
||||||
};
|
};
|
||||||
|
|
||||||
_updateFilter = (e) => {
|
_updateFilter = (e) => {
|
||||||
|
@ -735,6 +796,12 @@ export default class DMInviteDialog extends React.PureComponent {
|
||||||
render() {
|
render() {
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||||
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
|
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
|
||||||
|
const Spinner = sdk.getComponent("elements.Spinner");
|
||||||
|
|
||||||
|
let spinner = null;
|
||||||
|
if (this.state.busy) {
|
||||||
|
spinner = <Spinner w={20} h={20} />;
|
||||||
|
}
|
||||||
|
|
||||||
const userId = MatrixClientPeg.get().getUserId();
|
const userId = MatrixClientPeg.get().getUserId();
|
||||||
return (
|
return (
|
||||||
|
@ -755,15 +822,20 @@ export default class DMInviteDialog extends React.PureComponent {
|
||||||
</p>
|
</p>
|
||||||
<div className='mx_DMInviteDialog_addressBar'>
|
<div className='mx_DMInviteDialog_addressBar'>
|
||||||
{this._renderEditor()}
|
{this._renderEditor()}
|
||||||
{this._renderIdentityServerWarning()}
|
<div className='mx_DMInviteDialog_buttonAndSpinner'>
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
kind="primary"
|
kind="primary"
|
||||||
onClick={this._startDm}
|
onClick={this._startDm}
|
||||||
className='mx_DMInviteDialog_goButton'
|
className='mx_DMInviteDialog_goButton'
|
||||||
>
|
disabled={this.state.busy}
|
||||||
{_t("Go")}
|
>
|
||||||
</AccessibleButton>
|
{_t("Go")}
|
||||||
|
</AccessibleButton>
|
||||||
|
{spinner}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{this._renderIdentityServerWarning()}
|
||||||
|
<div className='error'>{this.state.errorText}</div>
|
||||||
{this._renderSection('recents')}
|
{this._renderSection('recents')}
|
||||||
{this._renderSection('suggestions')}
|
{this._renderSection('suggestions')}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1423,6 +1423,8 @@
|
||||||
"View Servers in Room": "View Servers in Room",
|
"View Servers in Room": "View Servers in Room",
|
||||||
"Toolbox": "Toolbox",
|
"Toolbox": "Toolbox",
|
||||||
"Developer Tools": "Developer Tools",
|
"Developer Tools": "Developer Tools",
|
||||||
|
"Failed to invite the following users to chat: %(csvUsers)s": "Failed to invite the following users to chat: %(csvUsers)s",
|
||||||
|
"We couldn't create your DM. Please check the users you want to invite and try again.": "We couldn't create your DM. Please check the users you want to invite and try again.",
|
||||||
"Failed to find the following users": "Failed to find the following users",
|
"Failed to find the following users": "Failed to find the following users",
|
||||||
"The following users might not exist or are invalid, and cannot be invited: %(csvNames)s": "The following users might not exist or are invalid, and cannot be invited: %(csvNames)s",
|
"The following users might not exist or are invalid, and cannot be invited: %(csvNames)s": "The following users might not exist or are invalid, and cannot be invited: %(csvNames)s",
|
||||||
"Recent Conversations": "Recent Conversations",
|
"Recent Conversations": "Recent Conversations",
|
||||||
|
|
|
@ -124,6 +124,27 @@ export default class DMRoomMap {
|
||||||
return this._getUserToRooms()[userId] || [];
|
return this._getUserToRooms()[userId] || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the DM room which the given IDs share, if any.
|
||||||
|
* @param {string[]} ids The identifiers (user IDs and email addresses) to look for.
|
||||||
|
* @returns {Room} The DM room which all IDs given share, or falsey if no common room.
|
||||||
|
*/
|
||||||
|
getDMRoomForIdentifiers(ids) {
|
||||||
|
// TODO: [Canonical DMs] Handle lookups for email addresses.
|
||||||
|
// For now we'll pretend we only get user IDs and end up returning nothing for email addresses
|
||||||
|
|
||||||
|
let commonRooms = this.getDMRoomsForUserId(ids[0]);
|
||||||
|
for (let i = 1; i < ids.length; i++) {
|
||||||
|
const userRooms = this.getDMRoomsForUserId(ids[i]);
|
||||||
|
commonRooms = commonRooms.filter(r => userRooms.includes(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
const joinedRooms = commonRooms.map(r => MatrixClientPeg.get().getRoom(r))
|
||||||
|
.filter(r => r && r.getMyMembership() === 'join');
|
||||||
|
|
||||||
|
return joinedRooms[0];
|
||||||
|
}
|
||||||
|
|
||||||
getUserIdForRoomId(roomId) {
|
getUserIdForRoomId(roomId) {
|
||||||
if (this.roomToUser == null) {
|
if (this.roomToUser == null) {
|
||||||
// we lazily populate roomToUser so you can use
|
// we lazily populate roomToUser so you can use
|
||||||
|
|
Loading…
Reference in a new issue