mirror of https://github.com/vector-im/riot-web
				
				
				
			Merge remote-tracking branch 'origin/develop' into dbkr/roomcreate
						commit
						c40ac49b2a
					
				| 
						 | 
				
			
			@ -1,3 +1,10 @@
 | 
			
		|||
Changes in [0.13.2](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.13.2) (2018-08-23)
 | 
			
		||||
=====================================================================================================
 | 
			
		||||
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.13.1...v0.13.2)
 | 
			
		||||
 | 
			
		||||
 * Don't crash if the value of a room tag is null
 | 
			
		||||
   [\#2135](https://github.com/matrix-org/matrix-react-sdk/pull/2135)
 | 
			
		||||
 | 
			
		||||
Changes in [0.13.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.13.1) (2018-08-20)
 | 
			
		||||
=====================================================================================================
 | 
			
		||||
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.13.1-rc.1...v0.13.1)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
{
 | 
			
		||||
  "name": "matrix-react-sdk",
 | 
			
		||||
  "version": "0.13.1",
 | 
			
		||||
  "version": "0.13.2",
 | 
			
		||||
  "description": "SDK for matrix.org using React",
 | 
			
		||||
  "author": "matrix.org",
 | 
			
		||||
  "repository": {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,6 +39,7 @@
 | 
			
		|||
@import "./views/dialogs/_EncryptedEventDialog.scss";
 | 
			
		||||
@import "./views/dialogs/_GroupAddressPicker.scss";
 | 
			
		||||
@import "./views/dialogs/_QuestionDialog.scss";
 | 
			
		||||
@import "./views/dialogs/_RoomUpgradeDialog.scss";
 | 
			
		||||
@import "./views/dialogs/_SetEmailDialog.scss";
 | 
			
		||||
@import "./views/dialogs/_SetMxIdDialog.scss";
 | 
			
		||||
@import "./views/dialogs/_SetPasswordDialog.scss";
 | 
			
		||||
| 
						 | 
				
			
			@ -100,6 +101,7 @@
 | 
			
		|||
@import "./views/rooms/_RoomSettings.scss";
 | 
			
		||||
@import "./views/rooms/_RoomTile.scss";
 | 
			
		||||
@import "./views/rooms/_RoomTooltip.scss";
 | 
			
		||||
@import "./views/rooms/_RoomUpgradeWarningBar.scss";
 | 
			
		||||
@import "./views/rooms/_SearchBar.scss";
 | 
			
		||||
@import "./views/rooms/_SearchableEntityList.scss";
 | 
			
		||||
@import "./views/rooms/_Stickers.scss";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2018 New Vector Ltd
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
.mx_RoomUpgradeDialog {
 | 
			
		||||
    padding-right: 70px;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -20,6 +20,7 @@ limitations under the License.
 | 
			
		|||
    margin-bottom: 20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_RoomSettings_upgradeButton,
 | 
			
		||||
.mx_RoomSettings_leaveButton,
 | 
			
		||||
.mx_RoomSettings_unbanButton {
 | 
			
		||||
    @mixin mx_DialogButton;
 | 
			
		||||
| 
						 | 
				
			
			@ -27,11 +28,16 @@ limitations under the License.
 | 
			
		|||
    margin-right: 8px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_RoomSettings_upgradeButton,
 | 
			
		||||
.mx_RoomSettings_leaveButton:hover,
 | 
			
		||||
.mx_RoomSettings_unbanButton:hover {
 | 
			
		||||
    @mixin mx_DialogButton_hover;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_RoomSettings_upgradeButton.danger {
 | 
			
		||||
    @mixin mx_DialogButton_danger;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_RoomSettings_integrationsButton_error {
 | 
			
		||||
    position: relative;
 | 
			
		||||
    cursor: not-allowed;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,48 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2018 New Vector Ltd
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
.mx_RoomUpgradeWarningBar {
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    height: 176px;
 | 
			
		||||
    background-color: $event-selected-color;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    background-color: $preview-bar-bg-color;
 | 
			
		||||
    -webkit-align-items: center;
 | 
			
		||||
    padding-left: 20px;
 | 
			
		||||
    padding-right: 20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_RoomUpgradeWarningBar_header {
 | 
			
		||||
    color: $warning-color;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_RoomUpgradeWarningBar_body {
 | 
			
		||||
    color: $warning-color;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_RoomUpgradeWarningBar_upgradelink {
 | 
			
		||||
    color: $warning-color;
 | 
			
		||||
    text-decoration: underline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_RoomUpgradeWarningBar_small {
 | 
			
		||||
    color: $greyed-fg-color;
 | 
			
		||||
    font-size: 70%;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -171,6 +171,10 @@ $progressbar-color: #000;
 | 
			
		|||
    outline: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@define-mixin mx_DialogButton_danger {
 | 
			
		||||
    background-color: $warning-color;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@define-mixin mx_DialogButton_hover {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -480,7 +480,7 @@ function getMembershipCount(event, roomId) {
 | 
			
		|||
        sendError(event, _t('This room is not recognised.'));
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    const count = room.getJoinedMembers().length;
 | 
			
		||||
    const count = room.getJoinedMemberCount();
 | 
			
		||||
    sendResponse(event, count);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -497,12 +497,11 @@ function canSendEvent(event, roomId) {
 | 
			
		|||
        sendError(event, _t('This room is not recognised.'));
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    const me = client.credentials.userId;
 | 
			
		||||
    const member = room.getMember(me);
 | 
			
		||||
    if (!member || member.membership !== "join") {
 | 
			
		||||
    if (room.getMyMembership() !== "join") {
 | 
			
		||||
        sendError(event, _t('You are not in this room.'));
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    const me = client.credentials.userId;
 | 
			
		||||
 | 
			
		||||
    let canSend = false;
 | 
			
		||||
    if (isState) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -72,7 +72,7 @@ ConferenceCall.prototype._getConferenceUserRoom = function() {
 | 
			
		|||
    for (var i = 0; i < rooms.length; i++) {
 | 
			
		||||
        var confUser = rooms[i].getMember(this.confUserId);
 | 
			
		||||
        if (confUser && confUser.membership === "join" &&
 | 
			
		||||
                rooms[i].getJoinedMembers().length === 2) {
 | 
			
		||||
                rooms[i].getJoinedMemberCount() === 2) {
 | 
			
		||||
            confRoom = rooms[i];
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -434,7 +434,10 @@ const LoggedInView = React.createClass({
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        const usageLimitEvent = this.state.serverNoticeEvents.find((e) => {
 | 
			
		||||
            return e && e.getType() === 'm.server_notice.usage_limit_reached';
 | 
			
		||||
            return (
 | 
			
		||||
                e && e.getType() === 'm.room.message' &&
 | 
			
		||||
                e.getContent()['server_notice_type'] === 'm.server_notice.usage_limit_reached'
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        let topBar;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -280,7 +280,7 @@ module.exports = React.createClass({
 | 
			
		|||
            const room = cli.getRoom(this.props.roomId);
 | 
			
		||||
            let isUserInRoom;
 | 
			
		||||
            if (room) {
 | 
			
		||||
                const numMembers = room.getJoinedMembers().length;
 | 
			
		||||
                const numMembers = room.getJoinedMemberCount();
 | 
			
		||||
                membersTitle = _t('%(count)s Members', { count: numMembers });
 | 
			
		||||
                membersBadge = <div title={membersTitle}>{ formatCount(numMembers) }</div>;
 | 
			
		||||
                isUserInRoom = room.hasMembershipState(this.context.matrixClient.credentials.userId, 'join');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -363,7 +363,7 @@ module.exports = React.createClass({
 | 
			
		|||
        // XXX: EVIL HACK to autofocus inviting on empty rooms.
 | 
			
		||||
        // We use the setTimeout to avoid racing with focus_composer.
 | 
			
		||||
        if (this.state.room &&
 | 
			
		||||
            this.state.room.getJoinedMembers().length == 1 &&
 | 
			
		||||
            this.state.room.getJoinedMemberCount() == 1 &&
 | 
			
		||||
            this.state.room.getLiveTimeline() &&
 | 
			
		||||
            this.state.room.getLiveTimeline().getEvents() &&
 | 
			
		||||
            this.state.room.getLiveTimeline().getEvents().length <= 6) {
 | 
			
		||||
| 
						 | 
				
			
			@ -701,7 +701,6 @@ module.exports = React.createClass({
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        this._updateRoomMembers();
 | 
			
		||||
        this._checkIfAlone(this.state.room);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onRoomMemberMembership: function(ev, member, oldMembership) {
 | 
			
		||||
| 
						 | 
				
			
			@ -717,6 +716,7 @@ module.exports = React.createClass({
 | 
			
		|||
        // refresh the conf call notification state
 | 
			
		||||
        this._updateConfCallNotification();
 | 
			
		||||
        this._updateDMState();
 | 
			
		||||
        this._checkIfAlone(this.state.room);
 | 
			
		||||
    }, 500),
 | 
			
		||||
 | 
			
		||||
    _checkIfAlone: function(room) {
 | 
			
		||||
| 
						 | 
				
			
			@ -729,8 +729,8 @@ module.exports = React.createClass({
 | 
			
		|||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const joinedMembers = room.currentState.getMembers().filter((m) => m.membership === "join" || m.membership === "invite");
 | 
			
		||||
        this.setState({isAlone: joinedMembers.length === 1});
 | 
			
		||||
        const joinedOrInvitedMemberCount = room.getJoinedMemberCount() + room.getInvitedMemberCount();
 | 
			
		||||
        this.setState({isAlone: joinedOrInvitedMemberCount === 1});
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateConfCallNotification: function() {
 | 
			
		||||
| 
						 | 
				
			
			@ -1461,6 +1461,7 @@ module.exports = React.createClass({
 | 
			
		|||
        const RoomPreviewBar = sdk.getComponent("rooms.RoomPreviewBar");
 | 
			
		||||
        const Loader = sdk.getComponent("elements.Spinner");
 | 
			
		||||
        const TimelinePanel = sdk.getComponent("structures.TimelinePanel");
 | 
			
		||||
        const RoomUpgradeWarningBar = sdk.getComponent("rooms.RoomUpgradeWarningBar");
 | 
			
		||||
 | 
			
		||||
        if (!this.state.room) {
 | 
			
		||||
            if (this.state.roomLoading || this.state.peekLoading) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1507,9 +1508,8 @@ module.exports = React.createClass({
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const myUserId = MatrixClientPeg.get().credentials.userId;
 | 
			
		||||
        const myMember = this.state.room.getMember(myUserId);
 | 
			
		||||
        if (myMember && myMember.membership == 'invite') {
 | 
			
		||||
        const myMembership = this.state.room.getMyMembership();
 | 
			
		||||
        if (myMembership == 'invite') {
 | 
			
		||||
            if (this.state.joining || this.state.rejecting) {
 | 
			
		||||
                return (
 | 
			
		||||
                    <div className="mx_RoomView">
 | 
			
		||||
| 
						 | 
				
			
			@ -1517,6 +1517,8 @@ module.exports = React.createClass({
 | 
			
		|||
                    </div>
 | 
			
		||||
                );
 | 
			
		||||
            } else {
 | 
			
		||||
                const myUserId = MatrixClientPeg.get().credentials.userId;
 | 
			
		||||
                const myMember = this.state.room.getMember(myUserId);
 | 
			
		||||
                const inviteEvent = myMember.events.member;
 | 
			
		||||
                var inviterName = inviteEvent.sender ? inviteEvent.sender.name : inviteEvent.getSender();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1586,6 +1588,11 @@ module.exports = React.createClass({
 | 
			
		|||
            />;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const showRoomUpgradeBar = (
 | 
			
		||||
            this.state.room.shouldUpgradeToVersion() &&
 | 
			
		||||
            this.state.room.userMayUpgradeRoom(MatrixClientPeg.get().credentials.userId)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let aux = null;
 | 
			
		||||
        let hideCancel = false;
 | 
			
		||||
        if (this.state.editingRoomSettings) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1597,10 +1604,13 @@ module.exports = React.createClass({
 | 
			
		|||
        } else if (this.state.searching) {
 | 
			
		||||
            hideCancel = true; // has own cancel
 | 
			
		||||
            aux = <SearchBar ref="search_bar" searchInProgress={this.state.searchInProgress} onCancelClick={this.onCancelSearchClick} onSearch={this.onSearch} />;
 | 
			
		||||
        } else if (showRoomUpgradeBar) {
 | 
			
		||||
            aux = <RoomUpgradeWarningBar room={this.state.room} />;
 | 
			
		||||
            hideCancel = true;
 | 
			
		||||
        } else if (this.state.showingPinned) {
 | 
			
		||||
            hideCancel = true; // has own cancel
 | 
			
		||||
            aux = <PinnedEventsPanel room={this.state.room} onCancelClick={this.onPinnedClick} />;
 | 
			
		||||
        } else if (!myMember || myMember.membership !== "join") {
 | 
			
		||||
        } else if (myMembership !== "join") {
 | 
			
		||||
            // We do have a room object for this room, but we're not currently in it.
 | 
			
		||||
            // We may have a 3rd party invite to it.
 | 
			
		||||
            var inviterName = undefined;
 | 
			
		||||
| 
						 | 
				
			
			@ -1642,7 +1652,7 @@ module.exports = React.createClass({
 | 
			
		|||
        let messageComposer, searchInfo;
 | 
			
		||||
        const canSpeak = (
 | 
			
		||||
            // joined and not showing search results
 | 
			
		||||
            myMember && (myMember.membership == 'join') && !this.state.searchResults
 | 
			
		||||
            myMembership == 'join' && !this.state.searchResults
 | 
			
		||||
        );
 | 
			
		||||
        if (canSpeak) {
 | 
			
		||||
            messageComposer =
 | 
			
		||||
| 
						 | 
				
			
			@ -1777,15 +1787,15 @@ module.exports = React.createClass({
 | 
			
		|||
                    oobData={this.props.oobData}
 | 
			
		||||
                    editing={this.state.editingRoomSettings}
 | 
			
		||||
                    saving={this.state.uploadingRoomSettings}
 | 
			
		||||
                    inRoom={myMember && myMember.membership === 'join'}
 | 
			
		||||
                    inRoom={myMembership === 'join'}
 | 
			
		||||
                    collapsedRhs={this.props.collapsedRhs}
 | 
			
		||||
                    onSearchClick={this.onSearchClick}
 | 
			
		||||
                    onSettingsClick={this.onSettingsClick}
 | 
			
		||||
                    onPinnedClick={this.onPinnedClick}
 | 
			
		||||
                    onSaveClick={this.onSettingsSaveClick}
 | 
			
		||||
                    onCancelClick={(aux && !hideCancel) ? this.onCancelClick : null}
 | 
			
		||||
                    onForgetClick={(myMember && myMember.membership === "leave") ? this.onForgetClick : null}
 | 
			
		||||
                    onLeaveClick={(myMember && myMember.membership === "join") ? this.onLeaveClick : null}
 | 
			
		||||
                    onForgetClick={(myMembership === "leave") ? this.onForgetClick : null}
 | 
			
		||||
                    onLeaveClick={(myMembership === "join") ? this.onLeaveClick : null}
 | 
			
		||||
                />
 | 
			
		||||
                { auxPanel }
 | 
			
		||||
                <div className={fadableSectionClasses}>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -921,6 +921,25 @@ module.exports = React.createClass({
 | 
			
		|||
        </div>;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _renderTermsAndConditionsLinks: function() {
 | 
			
		||||
        if (SdkConfig.get().terms_and_conditions_links) {
 | 
			
		||||
            const tncLinks = [];
 | 
			
		||||
            for (const tncEntry of SdkConfig.get().terms_and_conditions_links) {
 | 
			
		||||
                tncLinks.push(<div key={tncEntry.url}>
 | 
			
		||||
                    <a href={tncEntry.url} rel="noopener" target="_blank">{tncEntry.text}</a>
 | 
			
		||||
                </div>);
 | 
			
		||||
            }
 | 
			
		||||
            return <div>
 | 
			
		||||
                <h3>{ _t("Legal") }</h3>
 | 
			
		||||
                <div className="mx_UserSettings_section">
 | 
			
		||||
                    {tncLinks}
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>;
 | 
			
		||||
        } else {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _renderClearCache: function() {
 | 
			
		||||
        return <div>
 | 
			
		||||
            <h3>{ _t("Clear Cache") }</h3>
 | 
			
		||||
| 
						 | 
				
			
			@ -1407,6 +1426,8 @@ module.exports = React.createClass({
 | 
			
		|||
 | 
			
		||||
                { this._renderDeactivateAccount() }
 | 
			
		||||
 | 
			
		||||
                { this._renderTermsAndConditionsLinks() }
 | 
			
		||||
 | 
			
		||||
                </GeminiScrollbarWrapper>
 | 
			
		||||
            </div>
 | 
			
		||||
        );
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,7 @@ import {ContentRepo} from "matrix-js-sdk";
 | 
			
		|||
import MatrixClientPeg from "../../../MatrixClientPeg";
 | 
			
		||||
import Modal from '../../../Modal';
 | 
			
		||||
import sdk from "../../../index";
 | 
			
		||||
import DMRoomMap from '../../../utils/DMRoomMap';
 | 
			
		||||
 | 
			
		||||
module.exports = React.createClass({
 | 
			
		||||
    displayName: 'RoomAvatar',
 | 
			
		||||
| 
						 | 
				
			
			@ -107,58 +108,37 @@ module.exports = React.createClass({
 | 
			
		|||
    },
 | 
			
		||||
 | 
			
		||||
    getOneToOneAvatar: function(props) {
 | 
			
		||||
        if (!props.room) return null;
 | 
			
		||||
 | 
			
		||||
        const mlist = props.room.currentState.members;
 | 
			
		||||
        const userIds = [];
 | 
			
		||||
        const leftUserIds = [];
 | 
			
		||||
        // for .. in optimisation to return early if there are >2 keys
 | 
			
		||||
        for (const uid in mlist) {
 | 
			
		||||
            if (mlist.hasOwnProperty(uid)) {
 | 
			
		||||
                if (["join", "invite"].includes(mlist[uid].membership)) {
 | 
			
		||||
                    userIds.push(uid);
 | 
			
		||||
                } else {
 | 
			
		||||
                    leftUserIds.push(uid);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (userIds.length > 2) {
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
        const room = props.room;
 | 
			
		||||
        if (!room) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (userIds.length == 2) {
 | 
			
		||||
            let theOtherGuy = null;
 | 
			
		||||
            if (mlist[userIds[0]].userId == MatrixClientPeg.get().credentials.userId) {
 | 
			
		||||
                theOtherGuy = mlist[userIds[1]];
 | 
			
		||||
            } else {
 | 
			
		||||
                theOtherGuy = mlist[userIds[0]];
 | 
			
		||||
            }
 | 
			
		||||
            return theOtherGuy.getAvatarUrl(
 | 
			
		||||
                MatrixClientPeg.get().getHomeserverUrl(),
 | 
			
		||||
                Math.floor(props.width * window.devicePixelRatio),
 | 
			
		||||
                Math.floor(props.height * window.devicePixelRatio),
 | 
			
		||||
                props.resizeMethod,
 | 
			
		||||
                false,
 | 
			
		||||
            );
 | 
			
		||||
        } else if (userIds.length == 1) {
 | 
			
		||||
            // The other 1-1 user left, leaving just the current user, so show the left user's avatar
 | 
			
		||||
            if (leftUserIds.length === 1) {
 | 
			
		||||
                return mlist[leftUserIds[0]].getAvatarUrl(
 | 
			
		||||
                    MatrixClientPeg.get().getHomeserverUrl(),
 | 
			
		||||
                    props.width, props.height, props.resizeMethod,
 | 
			
		||||
                    false,
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
            return mlist[userIds[0]].getAvatarUrl(
 | 
			
		||||
                MatrixClientPeg.get().getHomeserverUrl(),
 | 
			
		||||
                Math.floor(props.width * window.devicePixelRatio),
 | 
			
		||||
                Math.floor(props.height * window.devicePixelRatio),
 | 
			
		||||
                props.resizeMethod,
 | 
			
		||||
                false,
 | 
			
		||||
            );
 | 
			
		||||
        let otherMember = null;
 | 
			
		||||
        const otherUserId = DMRoomMap.shared().getUserIdForRoomId(room.roomId);
 | 
			
		||||
        if (otherUserId) {
 | 
			
		||||
            otherMember = room.getMember(otherUserId);
 | 
			
		||||
        } else {
 | 
			
		||||
           return null;
 | 
			
		||||
            // if the room is not marked as a 1:1, but only has max 2 members
 | 
			
		||||
            // then still try to show any avatar (pref. other member)
 | 
			
		||||
            const totalMemberCount = room.getJoinedMemberCount() +
 | 
			
		||||
                room.getInvitedMemberCount();
 | 
			
		||||
            const members = room.currentState.getMembers();
 | 
			
		||||
            if (totalMemberCount == 2) {
 | 
			
		||||
                const myUserId = MatrixClientPeg.get().getUserId();
 | 
			
		||||
                otherMember = members.find(m => m.userId !== myUserId);
 | 
			
		||||
            } else if (totalMemberCount == 1) {
 | 
			
		||||
                otherMember = members[0];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (otherMember) {
 | 
			
		||||
            return otherMember.getAvatarUrl(
 | 
			
		||||
                MatrixClientPeg.get().getHomeserverUrl(),
 | 
			
		||||
                Math.floor(props.width * window.devicePixelRatio),
 | 
			
		||||
                Math.floor(props.height * window.devicePixelRatio),
 | 
			
		||||
                props.resizeMethod,
 | 
			
		||||
                false,
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onRoomAvatarClick: function() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -346,20 +346,18 @@ module.exports = React.createClass({
 | 
			
		|||
    },
 | 
			
		||||
 | 
			
		||||
    render: function() {
 | 
			
		||||
        const myMember = this.props.room.getMember(
 | 
			
		||||
            MatrixClientPeg.get().credentials.userId,
 | 
			
		||||
        );
 | 
			
		||||
        const myMembership = this.props.room.getMyMembership();
 | 
			
		||||
 | 
			
		||||
        // Can't set notif level or tags on non-join rooms
 | 
			
		||||
        if (myMember.membership !== 'join') {
 | 
			
		||||
            return this._renderLeaveMenu(myMember.membership);
 | 
			
		||||
        if (myMembership !== 'join') {
 | 
			
		||||
            return this._renderLeaveMenu(myMembership);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (
 | 
			
		||||
            <div>
 | 
			
		||||
                { this._renderNotifMenu() }
 | 
			
		||||
                <hr className="mx_RoomTileContextMenu_separator" />
 | 
			
		||||
                { this._renderLeaveMenu(myMember.membership) }
 | 
			
		||||
                { this._renderLeaveMenu(myMembership) }
 | 
			
		||||
                <hr className="mx_RoomTileContextMenu_separator" />
 | 
			
		||||
                { this._renderRoomTagMenu() }
 | 
			
		||||
            </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,106 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2018 New Vector Ltd
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
import sdk from '../../../index';
 | 
			
		||||
import MatrixClientPeg from '../../../MatrixClientPeg';
 | 
			
		||||
import Modal from '../../../Modal';
 | 
			
		||||
import { _t } from '../../../languageHandler';
 | 
			
		||||
 | 
			
		||||
export default React.createClass({
 | 
			
		||||
    displayName: 'RoomUpgradeDialog',
 | 
			
		||||
 | 
			
		||||
    propTypes: {
 | 
			
		||||
        room: PropTypes.object.isRequired,
 | 
			
		||||
        onFinished: PropTypes.func.isRequired,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    componentWillMount: function() {
 | 
			
		||||
        this._targetVersion = this.props.room.shouldUpgradeToVersion();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getInitialState: function() {
 | 
			
		||||
        return {
 | 
			
		||||
            busy: false,
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onCancelClick: function() {
 | 
			
		||||
        this.props.onFinished(false);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onUpgradeClick: function() {
 | 
			
		||||
        this.setState({busy: true});
 | 
			
		||||
        MatrixClientPeg.get().upgradeRoom(this.props.room.roomId, this._targetVersion).catch((err) => {
 | 
			
		||||
            const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
 | 
			
		||||
            Modal.createTrackedDialog('Failed to upgrade room', '', ErrorDialog, {
 | 
			
		||||
                title: _t("Failed to upgrade room"),
 | 
			
		||||
                description: ((err && err.message) ? err.message : _t("The room upgrade could not be completed")),
 | 
			
		||||
            });
 | 
			
		||||
        }).finally(() => {
 | 
			
		||||
            this.setState({busy: false});
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    render: function() {
 | 
			
		||||
        const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
 | 
			
		||||
        const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
 | 
			
		||||
        const Spinner = sdk.getComponent('views.elements.Spinner');
 | 
			
		||||
 | 
			
		||||
        let buttons;
 | 
			
		||||
        if (this.state.busy) {
 | 
			
		||||
            buttons = <Spinner />;
 | 
			
		||||
        } else {
 | 
			
		||||
            buttons = <DialogButtons
 | 
			
		||||
                primaryButton={_t(
 | 
			
		||||
                    'Upgrade this room to version %(version)s',
 | 
			
		||||
                    {version: this._targetVersion},
 | 
			
		||||
                )}
 | 
			
		||||
                primaryButtonClass="danger"
 | 
			
		||||
                hasCancel={true}
 | 
			
		||||
                onPrimaryButtonClick={this._onUpgradeClick}
 | 
			
		||||
                focus={this.props.focus}
 | 
			
		||||
                onCancel={this._onCancelClick}
 | 
			
		||||
            />;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (
 | 
			
		||||
            <BaseDialog className="mx_RoomUpgradeDialog"
 | 
			
		||||
                onFinished={this.onCancelled}
 | 
			
		||||
                title={_t("Upgrade Room Version")}
 | 
			
		||||
                contentId='mx_Dialog_content'
 | 
			
		||||
                onFinished={this.props.onFinished}
 | 
			
		||||
                hasCancel={true}
 | 
			
		||||
            >
 | 
			
		||||
                <p>
 | 
			
		||||
                    {_t(
 | 
			
		||||
                        "Upgrading this room requires closing down the current " +
 | 
			
		||||
                        "instance of the room and creating a new room it its place. " +
 | 
			
		||||
                        "To give room members the best possible experience, we will:",
 | 
			
		||||
                    )}
 | 
			
		||||
                </p>
 | 
			
		||||
                <ol>
 | 
			
		||||
                    <li>{_t("Create a new room with the same name, description and avatar")}</li>
 | 
			
		||||
                    <li>{_t("Update any local room aliases to point to the new room")}</li>
 | 
			
		||||
                    <li>{_t("Stop users from speaking in the old version of the room, and post a message advising users to move to the new room")}</li>
 | 
			
		||||
                    <li>{_t("Put a link back to the old room at the start of the new room so people can see old messages")}</li>
 | 
			
		||||
                </ol>
 | 
			
		||||
                {buttons}
 | 
			
		||||
            </BaseDialog>
 | 
			
		||||
        );
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -71,6 +71,23 @@ export default class MessageComposer extends React.Component {
 | 
			
		|||
        // XXX: fragile as all hell - fixme somehow, perhaps with a dedicated Room.encryption event or something.
 | 
			
		||||
        MatrixClientPeg.get().on("event", this.onEvent);
 | 
			
		||||
        this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
 | 
			
		||||
        this._waitForOwnMember();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _waitForOwnMember() {
 | 
			
		||||
        // if we have the member already, do that
 | 
			
		||||
        const me = this.props.room.getMember(MatrixClientPeg.get().getUserId());
 | 
			
		||||
        if (me) {
 | 
			
		||||
            this.setState({me});
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        // Otherwise, wait for member loading to finish and then update the member for the avatar.
 | 
			
		||||
        // The members should already be loading, and loadMembersIfNeeded
 | 
			
		||||
        // will return the promise for the existing operation
 | 
			
		||||
        this.props.room.loadMembersIfNeeded().then(() => {
 | 
			
		||||
            const me = this.props.room.getMember(MatrixClientPeg.get().getUserId());
 | 
			
		||||
            this.setState({me});
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    componentWillUnmount() {
 | 
			
		||||
| 
						 | 
				
			
			@ -208,7 +225,6 @@ export default class MessageComposer extends React.Component {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    render() {
 | 
			
		||||
        const me = this.props.room.getMember(MatrixClientPeg.get().credentials.userId);
 | 
			
		||||
        const uploadInputStyle = {display: 'none'};
 | 
			
		||||
        const MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
 | 
			
		||||
        const TintableSvg = sdk.getComponent("elements.TintableSvg");
 | 
			
		||||
| 
						 | 
				
			
			@ -216,11 +232,13 @@ export default class MessageComposer extends React.Component {
 | 
			
		|||
 | 
			
		||||
        const controls = [];
 | 
			
		||||
 | 
			
		||||
        controls.push(
 | 
			
		||||
            <div key="controls_avatar" className="mx_MessageComposer_avatar">
 | 
			
		||||
                <MemberAvatar member={me} width={24} height={24} />
 | 
			
		||||
            </div>,
 | 
			
		||||
        );
 | 
			
		||||
        if (this.state.me) {
 | 
			
		||||
            controls.push(
 | 
			
		||||
                <div key="controls_avatar" className="mx_MessageComposer_avatar">
 | 
			
		||||
                    <MemberAvatar member={this.state.me} width={24} height={24} />
 | 
			
		||||
                </div>,
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let e2eImg, e2eTitle, e2eClass;
 | 
			
		||||
        const roomIsEncrypted = MatrixClientPeg.get().isRoomEncrypted(this.props.room.roomId);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -97,7 +97,7 @@ module.exports = React.createClass({
 | 
			
		|||
        };
 | 
			
		||||
        // All rooms that should be kept in the room list when filtering.
 | 
			
		||||
        // By default, show all rooms.
 | 
			
		||||
        this._visibleRooms = MatrixClientPeg.get().getRooms();
 | 
			
		||||
        this._visibleRooms = MatrixClientPeg.get().getVisibleRooms();
 | 
			
		||||
 | 
			
		||||
        // Listen to updates to group data. RoomList cares about members and rooms in order
 | 
			
		||||
        // to filter the room list when group tags are selected.
 | 
			
		||||
| 
						 | 
				
			
			@ -302,7 +302,7 @@ module.exports = React.createClass({
 | 
			
		|||
            this._visibleRooms = Array.from(roomSet);
 | 
			
		||||
        } else {
 | 
			
		||||
            // Show all rooms
 | 
			
		||||
            this._visibleRooms = MatrixClientPeg.get().getRooms();
 | 
			
		||||
            this._visibleRooms = MatrixClientPeg.get().getVisibleRooms();
 | 
			
		||||
        }
 | 
			
		||||
        this._delayedRefreshRoomList();
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -572,6 +572,11 @@ module.exports = React.createClass({
 | 
			
		|||
        });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onRoomUpgradeClick: function() {
 | 
			
		||||
        const RoomUpgradeDialog = sdk.getComponent('dialogs.RoomUpgradeDialog');
 | 
			
		||||
        Modal.createTrackedDialog('Upgrade Room Version', '', RoomUpgradeDialog, {room: this.props.room});
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onRoomMemberMembership: function() {
 | 
			
		||||
        // Update, since our banned user list may have changed
 | 
			
		||||
        this.forceUpdate();
 | 
			
		||||
| 
						 | 
				
			
			@ -794,15 +799,15 @@ module.exports = React.createClass({
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        let leaveButton = null;
 | 
			
		||||
        const myMember = this.props.room.getMember(myUserId);
 | 
			
		||||
        if (myMember) {
 | 
			
		||||
            if (myMember.membership === "join") {
 | 
			
		||||
        const myMemberShip = this.props.room.getMyMembership();
 | 
			
		||||
        if (myMemberShip) {
 | 
			
		||||
            if (myMemberShip === "join") {
 | 
			
		||||
                leaveButton = (
 | 
			
		||||
                    <AccessibleButton className="mx_RoomSettings_leaveButton" onClick={this.onLeaveClick}>
 | 
			
		||||
                        { _t('Leave room') }
 | 
			
		||||
                    </AccessibleButton>
 | 
			
		||||
                );
 | 
			
		||||
            } else if (myMember.membership === "leave") {
 | 
			
		||||
            } else if (myMemberShip === "leave") {
 | 
			
		||||
                leaveButton = (
 | 
			
		||||
                    <AccessibleButton className="mx_RoomSettings_leaveButton" onClick={this.onForgetClick}>
 | 
			
		||||
                        { _t('Forget room') }
 | 
			
		||||
| 
						 | 
				
			
			@ -930,6 +935,13 @@ module.exports = React.createClass({
 | 
			
		|||
            );
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        let roomUpgradeButton = null;
 | 
			
		||||
        if (this.props.room.shouldUpgradeToVersion() && this.props.room.userMayUpgradeRoom(myUserId)) {
 | 
			
		||||
            roomUpgradeButton = <AccessibleButton className="mx_RoomSettings_upgradeButton danger" onClick={this._onRoomUpgradeClick}>
 | 
			
		||||
                { _t("Upgrade room to version %(ver)s", {ver: this.props.room.shouldUpgradeToVersion()}) }
 | 
			
		||||
            </AccessibleButton>;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (
 | 
			
		||||
            <div className="mx_RoomSettings">
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1041,7 +1053,8 @@ module.exports = React.createClass({
 | 
			
		|||
                <h3>{ _t('Advanced') }</h3>
 | 
			
		||||
                <div className="mx_RoomSettings_settings">
 | 
			
		||||
                    { _t('Internal room ID: ') } <code>{ this.props.room.roomId }</code><br />
 | 
			
		||||
                    { _t('Room version number: ') } <code>{ this.props.room.getVersion() }</code>
 | 
			
		||||
                    { _t('Room version number: ') } <code>{ this.props.room.getVersion() }</code><br />
 | 
			
		||||
                    { roomUpgradeButton }
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        );
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,57 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2018 New Vector Ltd
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
import sdk from '../../../index';
 | 
			
		||||
import Modal from '../../../Modal';
 | 
			
		||||
 | 
			
		||||
import { _t } from '../../../languageHandler';
 | 
			
		||||
 | 
			
		||||
module.exports = React.createClass({
 | 
			
		||||
    displayName: 'RoomUpgradeWarningBar',
 | 
			
		||||
 | 
			
		||||
    propTypes: {
 | 
			
		||||
        room: PropTypes.object.isRequired,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onUpgradeClick: function() {
 | 
			
		||||
        const RoomUpgradeDialog = sdk.getComponent('dialogs.RoomUpgradeDialog');
 | 
			
		||||
        Modal.createTrackedDialog('Upgrade Room Version', '', RoomUpgradeDialog, {room: this.props.room});
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    render: function() {
 | 
			
		||||
        const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
 | 
			
		||||
        return (
 | 
			
		||||
            <div className="mx_RoomUpgradeWarningBar">
 | 
			
		||||
                <div className="mx_RoomUpgradeWarningBar_header">
 | 
			
		||||
                    {_t("There is a known vulnerability affecting this room.")}
 | 
			
		||||
                </div>
 | 
			
		||||
                <div className="mx_RoomUpgradeWarningBar_body">
 | 
			
		||||
                    {_t("This room version is vulnerable to malicious modification of room state.")}
 | 
			
		||||
                </div>
 | 
			
		||||
                <p className="mx_RoomUpgradeWarningBar_upgradelink">
 | 
			
		||||
                    <AccessibleButton onClick={this.onUpgradeClick}>
 | 
			
		||||
                        {_t("Click here to upgrade to the latest room version and ensure room integrity is protected.")}
 | 
			
		||||
                    </AccessibleButton>
 | 
			
		||||
                </p>
 | 
			
		||||
                <div className="mx_RoomUpgradeWarningBar_small">
 | 
			
		||||
                    {_t("Only room administrators will see this warning")}
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        );
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -203,6 +203,8 @@
 | 
			
		|||
    "Your browser does not support the required cryptography extensions": "Your browser does not support the required cryptography extensions",
 | 
			
		||||
    "Not a valid Riot keyfile": "Not a valid Riot keyfile",
 | 
			
		||||
    "Authentication check failed: incorrect password?": "Authentication check failed: incorrect password?",
 | 
			
		||||
    "Sorry, your homeserver is too old to participate in this room.": "Sorry, your homeserver is too old to participate in this room.",
 | 
			
		||||
    "Please contact your homeserver administrator.": "Please contact your homeserver administrator.",
 | 
			
		||||
    "Failed to join room": "Failed to join room",
 | 
			
		||||
    "Message Pinning": "Message Pinning",
 | 
			
		||||
    "Increase performance by only loading room members on first view": "Increase performance by only loading room members on first view",
 | 
			
		||||
| 
						 | 
				
			
			@ -529,6 +531,7 @@
 | 
			
		|||
    "Guests cannot join this room even if explicitly invited.": "Guests cannot join this room even if explicitly invited.",
 | 
			
		||||
    "Click here to fix": "Click here to fix",
 | 
			
		||||
    "To send events of type <eventType/>, you must be a": "To send events of type <eventType/>, you must be a",
 | 
			
		||||
    "Upgrade room to version %(ver)s": "Upgrade room to version %(ver)s",
 | 
			
		||||
    "Who can access this room?": "Who can access this room?",
 | 
			
		||||
    "Only people who have been invited": "Only people who have been invited",
 | 
			
		||||
    "Anyone who knows the room's link, apart from guests": "Anyone who knows the room's link, apart from guests",
 | 
			
		||||
| 
						 | 
				
			
			@ -544,6 +547,10 @@
 | 
			
		|||
    "Internal room ID: ": "Internal room ID: ",
 | 
			
		||||
    "Room version number: ": "Room version number: ",
 | 
			
		||||
    "Add a topic": "Add a topic",
 | 
			
		||||
    "There is a known vulnerability affecting this room.": "There is a known vulnerability affecting this room.",
 | 
			
		||||
    "This room version is vulnerable to malicious modification of room state.": "This room version is vulnerable to malicious modification of room state.",
 | 
			
		||||
    "Click here to upgrade to the latest room version and ensure room integrity is protected.": "Click here to upgrade to the latest room version and ensure room integrity is protected.",
 | 
			
		||||
    "Only room administrators will see this warning": "Only room administrators will see this warning",
 | 
			
		||||
    "Search…": "Search…",
 | 
			
		||||
    "This Room": "This Room",
 | 
			
		||||
    "All Rooms": "All Rooms",
 | 
			
		||||
| 
						 | 
				
			
			@ -864,6 +871,15 @@
 | 
			
		|||
    "Ignore request": "Ignore request",
 | 
			
		||||
    "Loading device info...": "Loading device info...",
 | 
			
		||||
    "Encryption key request": "Encryption key request",
 | 
			
		||||
    "Failed to upgrade room": "Failed to upgrade room",
 | 
			
		||||
    "The room upgrade could not be completed": "The room upgrade could not be completed",
 | 
			
		||||
    "Upgrade this room to version %(version)s": "Upgrade this room to version %(version)s",
 | 
			
		||||
    "Upgrade Room Version": "Upgrade Room Version",
 | 
			
		||||
    "Upgrading this room requires closing down the current instance of the room and creating a new room it its place. To give room members the best possible experience, we will:": "Upgrading this room requires closing down the current instance of the room and creating a new room it its place. To give room members the best possible experience, we will:",
 | 
			
		||||
    "Create a new room with the same name, description and avatar": "Create a new room with the same name, description and avatar",
 | 
			
		||||
    "Update any local room aliases to point to the new room": "Update any local room aliases to point to the new room",
 | 
			
		||||
    "Stop users from speaking in the old version of the room, and post a message advising users to move to the new room": "Stop users from speaking in the old version of the room, and post a message advising users to move to the new room",
 | 
			
		||||
    "Put a link back to the old room at the start of the new room so people can see old messages": "Put a link back to the old room at the start of the new room so people can see old messages",
 | 
			
		||||
    "Sign out": "Sign out",
 | 
			
		||||
    "Log out and remove encryption keys?": "Log out and remove encryption keys?",
 | 
			
		||||
    "Clear Storage and Sign Out": "Clear Storage and Sign Out",
 | 
			
		||||
| 
						 | 
				
			
			@ -1117,6 +1133,7 @@
 | 
			
		|||
    "Lazy loading members not supported": "Lazy loading members not supported",
 | 
			
		||||
    "Lazy loading is not supported by your current homeserver.": "Lazy loading is not supported by your current homeserver.",
 | 
			
		||||
    "Deactivate my account": "Deactivate my account",
 | 
			
		||||
    "Legal": "Legal",
 | 
			
		||||
    "Clear Cache": "Clear Cache",
 | 
			
		||||
    "Clear Cache and Reload": "Clear Cache and Reload",
 | 
			
		||||
    "Updates": "Updates",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -284,8 +284,8 @@ class RoomListStore extends Store {
 | 
			
		|||
            if (optimisticRequest && roomB === optimisticRequest.room) metaB = optimisticRequest.metaData;
 | 
			
		||||
 | 
			
		||||
            // Make sure the room tag has an order element, if not set it to be the bottom
 | 
			
		||||
            const a = metaA.order;
 | 
			
		||||
            const b = metaB.order;
 | 
			
		||||
            const a = metaA ? metaA.order : undefined;
 | 
			
		||||
            const b = metaB ? metaB.order : undefined;
 | 
			
		||||
 | 
			
		||||
            // Order undefined room tag orders to the bottom
 | 
			
		||||
            if (a === undefined && b !== undefined) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -223,7 +223,13 @@ class RoomViewStore extends Store {
 | 
			
		|||
                action: 'join_room_error',
 | 
			
		||||
                err: err,
 | 
			
		||||
            });
 | 
			
		||||
            const msg = err.message ? err.message : JSON.stringify(err);
 | 
			
		||||
            let msg = err.message ? err.message : JSON.stringify(err);
 | 
			
		||||
            if (err.errcode === 'M_INCOMPATIBLE_ROOM_VERSION') {
 | 
			
		||||
                msg = <div>
 | 
			
		||||
                    {_t("Sorry, your homeserver is too old to participate in this room.")}<br />
 | 
			
		||||
                    {_t("Please contact your homeserver administrator.")}
 | 
			
		||||
                </div>;
 | 
			
		||||
            }
 | 
			
		||||
            const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
 | 
			
		||||
            Modal.createTrackedDialog('Failed to join room', '', ErrorDialog, {
 | 
			
		||||
                title: _t("Failed to join room"),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -94,6 +94,7 @@ describe('RoomList', () => {
 | 
			
		|||
            createRoom({tags: {'m.lowpriority': {}}, name: 'Some unimportant room'}),
 | 
			
		||||
            createRoom({tags: {'custom.tag': {}}, name: 'Some room customly tagged'}),
 | 
			
		||||
        ];
 | 
			
		||||
        client.getVisibleRooms = client.getRooms;
 | 
			
		||||
 | 
			
		||||
        const roomMap = {};
 | 
			
		||||
        client.getRooms().forEach((r) => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -74,6 +74,7 @@ export function createTestClient() {
 | 
			
		|||
        getPushActionsForEvent: sinon.stub(),
 | 
			
		||||
        getRoom: sinon.stub().returns(mkStubRoom()),
 | 
			
		||||
        getRooms: sinon.stub().returns([]),
 | 
			
		||||
        getVisibleRooms: sinon.stub().returns([]),
 | 
			
		||||
        getGroups: sinon.stub().returns([]),
 | 
			
		||||
        loginFlows: sinon.stub(),
 | 
			
		||||
        on: sinon.stub(),
 | 
			
		||||
| 
						 | 
				
			
			@ -256,6 +257,8 @@ export function mkStubRoom(roomId = null) {
 | 
			
		|||
        getAccountData: () => null,
 | 
			
		||||
        hasMembershipState: () => null,
 | 
			
		||||
        getVersion: () => '1',
 | 
			
		||||
        shouldUpgradeToVersion: () => null,
 | 
			
		||||
        getMyMembership: () => "join",
 | 
			
		||||
        currentState: {
 | 
			
		||||
            getStateEvents: sinon.stub(),
 | 
			
		||||
            mayClientSendStateEvent: sinon.stub().returns(true),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue