Merge pull request #2757 from matrix-org/anoa/accept_all_invites

Ability to bulk accept all invites (and fix rejecting all invites)
This commit is contained in:
Travis Ralston 2019-03-08 14:55:59 -07:00 committed by GitHub
commit e1f9482107
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 74 additions and 23 deletions

View file

@ -40,6 +40,10 @@ limitations under the License.
margin-right: 10px; margin-right: 10px;
} }
.mx_SecurityUserSettingsTab_bulkOptions .mx_AccessibleButton {
margin-right: 10px;
}
.mx_SecurityUserSettingsTab_importExportButtons { .mx_SecurityUserSettingsTab_importExportButtons {
margin-bottom: 15px; margin-bottom: 15px;
} }

View file

@ -52,9 +52,13 @@ export default class SecurityUserSettingsTab extends React.Component {
constructor() { constructor() {
super(); super();
// Get number of rooms we're invited to
const invitedRooms = this._getInvitedRooms();
this.state = { this.state = {
ignoredUserIds: MatrixClientPeg.get().getIgnoredUsers(), ignoredUserIds: MatrixClientPeg.get().getIgnoredUsers(),
rejectingInvites: false, managingInvites: false,
invitedRoomAmt: invitedRooms.length,
}; };
} }
@ -93,24 +97,62 @@ export default class SecurityUserSettingsTab extends React.Component {
this.setState({ignoredUsers}); this.setState({ignoredUsers});
}; };
_onRejectAllInvitesClicked = (rooms, ev) => { _getInvitedRooms = () => {
return MatrixClientPeg.get().getRooms().filter((r) => {
return r.hasMembershipState(MatrixClientPeg.get().getUserId(), "invite");
});
};
_manageInvites = async (accept) => {
this.setState({ this.setState({
rejectingInvites: true, managingInvites: true,
}); });
// reject the invites
const promises = rooms.map((room) => { // Compile array of invitation room ids
return MatrixClientPeg.get().leave(room.roomId).catch((e) => { const invitedRoomIds = this._getInvitedRooms().map((room) => {
// purposefully drop errors to the floor: we'll just have a non-zero number on the UI return room.roomId;
// after trying to reject all the invites.
}); });
// Execute all acceptances/rejections sequentially
const self = this;
const cli = MatrixClientPeg.get();
const action = accept ? cli.joinRoom.bind(cli) : cli.leave.bind(cli);
for (let i = 0; i < invitedRoomIds.length; i++) {
const roomId = invitedRoomIds[i];
// Accept/reject invite
await action(roomId).then(() => {
// No error, update invited rooms button
this.setState({invitedRoomAmt: self.state.invitedRoomAmt - 1});
}, async (e) => {
// Action failure
if (e.errcode === "M_LIMIT_EXCEEDED") {
// Add a delay between each invite change in order to avoid rate
// limiting by the server.
await Promise.delay(e.retry_after_ms || 2500);
// Redo last action
i--;
} else {
// Print out error with joining/leaving room
console.warn(e);
}
}); });
Promise.all(promises).then(() => { }
this.setState({ this.setState({
rejectingInvites: false, managingInvites: false,
});
}); });
}; };
_onAcceptAllInvitesClicked = (ev) => {
this._manageInvites(true);
};
_onRejectAllInvitesClicked = (ev) => {
this._manageInvites(false);
};
_renderCurrentDeviceInfo() { _renderCurrentDeviceInfo() {
const SettingsFlag = sdk.getComponent('views.elements.SettingsFlag'); const SettingsFlag = sdk.getComponent('views.elements.SettingsFlag');
@ -173,21 +215,25 @@ export default class SecurityUserSettingsTab extends React.Component {
); );
} }
_renderRejectInvites() { _renderManageInvites() {
const invitedRooms = MatrixClientPeg.get().getRooms().filter((r) => { if (this.state.invitedRoomAmt === 0) {
return r.hasMembershipState(MatrixClientPeg.get().getUserId(), "invite");
});
if (invitedRooms.length === 0) {
return null; return null;
} }
const onClick = this._onRejectAllInvitesClicked.bind(this, invitedRooms); const invitedRooms = this._getInvitedRooms();
const InlineSpinner = sdk.getComponent('elements.InlineSpinner');
const onClickAccept = this._onAcceptAllInvitesClicked.bind(this, invitedRooms);
const onClickReject = this._onRejectAllInvitesClicked.bind(this, invitedRooms);
return ( return (
<div className='mx_SettingsTab_section'> <div className='mx_SettingsTab_section mx_SecurityUserSettingsTab_bulkOptions'>
<span className='mx_SettingsTab_subheading'>{_t('Bulk options')}</span> <span className='mx_SettingsTab_subheading'>{_t('Bulk options')}</span>
<AccessibleButton onClick={onClick} kind='danger' disabled={this.state.rejectingInvites}> <AccessibleButton onClick={onClickAccept} kind='primary' disabled={this.state.managingInvites}>
{_t("Reject all %(invitedRooms)s invites", {invitedRooms: invitedRooms.length})} {_t("Accept all %(invitedRooms)s invites", {invitedRooms: this.state.invitedRoomAmt})}
</AccessibleButton> </AccessibleButton>
<AccessibleButton onClick={onClickReject} kind='danger' disabled={this.state.managingInvites}>
{_t("Reject all %(invitedRooms)s invites", {invitedRooms: this.state.invitedRoomAmt})}
</AccessibleButton>
{this.state.managingInvites ? <InlineSpinner /> : <div />}
</div> </div>
); );
} }
@ -232,7 +278,7 @@ export default class SecurityUserSettingsTab extends React.Component {
onChange={this._updateAnalytics} /> onChange={this._updateAnalytics} />
</div> </div>
{this._renderIgnoredUsers()} {this._renderIgnoredUsers()}
{this._renderRejectInvites()} {this._renderManageInvites()}
</div> </div>
); );
} }

View file

@ -560,6 +560,7 @@
"Device key:": "Device key:", "Device key:": "Device key:",
"Ignored users": "Ignored users", "Ignored users": "Ignored users",
"Bulk options": "Bulk options", "Bulk options": "Bulk options",
"Accept all %(invitedRooms)s invites": "Accept all %(invitedRooms)s invites",
"Reject all %(invitedRooms)s invites": "Reject all %(invitedRooms)s invites", "Reject all %(invitedRooms)s invites": "Reject all %(invitedRooms)s invites",
"Key backup": "Key backup", "Key backup": "Key backup",
"Security & Privacy": "Security & Privacy", "Security & Privacy": "Security & Privacy",