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');
|
||||
|
|
|
@ -310,7 +310,7 @@ module.exports = React.createClass({
|
|||
});
|
||||
} else if (room) {
|
||||
//viewing a previously joined room, try to lazy load members
|
||||
|
||||
|
||||
// Stop peeking because we have joined this room previously
|
||||
MatrixClientPeg.get().stopPeeking();
|
||||
this.setState({isPeeking: false});
|
||||
|
@ -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