Merge remote-tracking branch 'origin/develop' into dbkr/room_upgrade

This commit is contained in:
David Baker 2018-08-29 15:51:07 +01:00
commit bd0a9cf3a0
18 changed files with 182 additions and 92 deletions

View file

@ -1,3 +1,61 @@
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)
* No changes since rc.1
Changes in [0.13.1-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.13.1-rc.1) (2018-08-16)
===============================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.13.0...v0.13.1-rc.1)
* Update from Weblate.
[\#2121](https://github.com/matrix-org/matrix-react-sdk/pull/2121)
* Shift to M_RESOURCE_LIMIT_EXCEEDED errors
[\#2120](https://github.com/matrix-org/matrix-react-sdk/pull/2120)
* Fix RoomSettings test
[\#2119](https://github.com/matrix-org/matrix-react-sdk/pull/2119)
* Show room version number in room settings
[\#2117](https://github.com/matrix-org/matrix-react-sdk/pull/2117)
* Warning bar for MAU limit hit
[\#2114](https://github.com/matrix-org/matrix-react-sdk/pull/2114)
* Recognise server notices room(s)
[\#2112](https://github.com/matrix-org/matrix-react-sdk/pull/2112)
* Update room tags behaviour to match spec more
[\#2111](https://github.com/matrix-org/matrix-react-sdk/pull/2111)
* while logging out ignore `Session.logged_out` as it is intentional
[\#2058](https://github.com/matrix-org/matrix-react-sdk/pull/2058)
* Don't show 'connection lost' bar on MAU error
[\#2110](https://github.com/matrix-org/matrix-react-sdk/pull/2110)
* Support MAU error on sync
[\#2108](https://github.com/matrix-org/matrix-react-sdk/pull/2108)
* Support active user limit on message send
[\#2106](https://github.com/matrix-org/matrix-react-sdk/pull/2106)
* Run end to end tests as part of Travis build
[\#2091](https://github.com/matrix-org/matrix-react-sdk/pull/2091)
* Remove package-lock.json for now
[\#2097](https://github.com/matrix-org/matrix-react-sdk/pull/2097)
* Support montly active user limit error on /login
[\#2103](https://github.com/matrix-org/matrix-react-sdk/pull/2103)
* Unpin sanitize-html
[\#2105](https://github.com/matrix-org/matrix-react-sdk/pull/2105)
* Pin sanitize-html to 0.18.2
[\#2101](https://github.com/matrix-org/matrix-react-sdk/pull/2101)
* Make clicking on side panels close settings (mk 3)
[\#2096](https://github.com/matrix-org/matrix-react-sdk/pull/2096)
* Fix persistent element location not updating
[\#2092](https://github.com/matrix-org/matrix-react-sdk/pull/2092)
* fix Devtools input autofocus && state traversal when len === 1 && key=""
[\#2090](https://github.com/matrix-org/matrix-react-sdk/pull/2090)
* allow autocompleting Emoji by common aliases, e.g :+1: to :thumbsup:
[\#2085](https://github.com/matrix-org/matrix-react-sdk/pull/2085)
Changes in [0.13.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.13.0) (2018-07-30) Changes in [0.13.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.13.0) (2018-07-30)
===================================================================================================== =====================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.13.0-rc.2...v0.13.0) [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.13.0-rc.2...v0.13.0)

View file

@ -1,6 +1,6 @@
{ {
"name": "matrix-react-sdk", "name": "matrix-react-sdk",
"version": "0.13.0", "version": "0.13.2",
"description": "SDK for matrix.org using React", "description": "SDK for matrix.org using React",
"author": "matrix.org", "author": "matrix.org",
"repository": { "repository": {
@ -73,7 +73,7 @@
"linkifyjs": "^2.1.6", "linkifyjs": "^2.1.6",
"lodash": "^4.13.1", "lodash": "^4.13.1",
"lolex": "2.3.2", "lolex": "2.3.2",
"matrix-js-sdk": "0.10.7", "matrix-js-sdk": "0.10.8",
"optimist": "^0.6.1", "optimist": "^0.6.1",
"pako": "^1.0.5", "pako": "^1.0.5",
"prop-types": "^15.5.8", "prop-types": "^15.5.8",

View file

@ -480,7 +480,7 @@ function getMembershipCount(event, roomId) {
sendError(event, _t('This room is not recognised.')); sendError(event, _t('This room is not recognised.'));
return; return;
} }
const count = room.getJoinedMembers().length; const count = room.getJoinedMemberCount();
sendResponse(event, count); sendResponse(event, count);
} }
@ -497,12 +497,11 @@ function canSendEvent(event, roomId) {
sendError(event, _t('This room is not recognised.')); sendError(event, _t('This room is not recognised.'));
return; return;
} }
const me = client.credentials.userId; if (room.getMyMembership() !== "join") {
const member = room.getMember(me);
if (!member || member.membership !== "join") {
sendError(event, _t('You are not in this room.')); sendError(event, _t('You are not in this room.'));
return; return;
} }
const me = client.credentials.userId;
let canSend = false; let canSend = false;
if (isState) { if (isState) {

View file

@ -72,7 +72,7 @@ ConferenceCall.prototype._getConferenceUserRoom = function() {
for (var i = 0; i < rooms.length; i++) { for (var i = 0; i < rooms.length; i++) {
var confUser = rooms[i].getMember(this.confUserId); var confUser = rooms[i].getMember(this.confUserId);
if (confUser && confUser.membership === "join" && if (confUser && confUser.membership === "join" &&
rooms[i].getJoinedMembers().length === 2) { rooms[i].getJoinedMemberCount() === 2) {
confRoom = rooms[i]; confRoom = rooms[i];
break; break;
} }

View file

@ -434,7 +434,10 @@ const LoggedInView = React.createClass({
} }
const usageLimitEvent = this.state.serverNoticeEvents.find((e) => { 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; let topBar;

View file

@ -280,7 +280,7 @@ module.exports = React.createClass({
const room = cli.getRoom(this.props.roomId); const room = cli.getRoom(this.props.roomId);
let isUserInRoom; let isUserInRoom;
if (room) { if (room) {
const numMembers = room.getJoinedMembers().length; const numMembers = room.getJoinedMemberCount();
membersTitle = _t('%(count)s Members', { count: numMembers }); membersTitle = _t('%(count)s Members', { count: numMembers });
membersBadge = <div title={membersTitle}>{ formatCount(numMembers) }</div>; membersBadge = <div title={membersTitle}>{ formatCount(numMembers) }</div>;
isUserInRoom = room.hasMembershipState(this.context.matrixClient.credentials.userId, 'join'); isUserInRoom = room.hasMembershipState(this.context.matrixClient.credentials.userId, 'join');

View file

@ -310,7 +310,7 @@ module.exports = React.createClass({
}); });
} else if (room) { } else if (room) {
//viewing a previously joined room, try to lazy load members //viewing a previously joined room, try to lazy load members
// Stop peeking because we have joined this room previously // Stop peeking because we have joined this room previously
MatrixClientPeg.get().stopPeeking(); MatrixClientPeg.get().stopPeeking();
this.setState({isPeeking: false}); this.setState({isPeeking: false});
@ -363,7 +363,7 @@ module.exports = React.createClass({
// XXX: EVIL HACK to autofocus inviting on empty rooms. // XXX: EVIL HACK to autofocus inviting on empty rooms.
// We use the setTimeout to avoid racing with focus_composer. // We use the setTimeout to avoid racing with focus_composer.
if (this.state.room && if (this.state.room &&
this.state.room.getJoinedMembers().length == 1 && this.state.room.getJoinedMemberCount() == 1 &&
this.state.room.getLiveTimeline() && this.state.room.getLiveTimeline() &&
this.state.room.getLiveTimeline().getEvents() && this.state.room.getLiveTimeline().getEvents() &&
this.state.room.getLiveTimeline().getEvents().length <= 6) { this.state.room.getLiveTimeline().getEvents().length <= 6) {
@ -701,7 +701,6 @@ module.exports = React.createClass({
} }
this._updateRoomMembers(); this._updateRoomMembers();
this._checkIfAlone(this.state.room);
}, },
onRoomMemberMembership: function(ev, member, oldMembership) { onRoomMemberMembership: function(ev, member, oldMembership) {
@ -717,6 +716,7 @@ module.exports = React.createClass({
// refresh the conf call notification state // refresh the conf call notification state
this._updateConfCallNotification(); this._updateConfCallNotification();
this._updateDMState(); this._updateDMState();
this._checkIfAlone(this.state.room);
}, 500), }, 500),
_checkIfAlone: function(room) { _checkIfAlone: function(room) {
@ -729,8 +729,8 @@ module.exports = React.createClass({
return; return;
} }
const joinedMembers = room.currentState.getMembers().filter((m) => m.membership === "join" || m.membership === "invite"); const joinedOrInvitedMemberCount = room.getJoinedMemberCount() + room.getInvitedMemberCount();
this.setState({isAlone: joinedMembers.length === 1}); this.setState({isAlone: joinedOrInvitedMemberCount === 1});
}, },
_updateConfCallNotification: function() { _updateConfCallNotification: function() {
@ -1508,9 +1508,8 @@ module.exports = React.createClass({
} }
} }
const myUserId = MatrixClientPeg.get().credentials.userId; const myMembership = this.state.room.getMyMembership();
const myMember = this.state.room.getMember(myUserId); if (myMembership == 'invite') {
if (myMember && myMember.membership == 'invite') {
if (this.state.joining || this.state.rejecting) { if (this.state.joining || this.state.rejecting) {
return ( return (
<div className="mx_RoomView"> <div className="mx_RoomView">
@ -1518,6 +1517,8 @@ module.exports = React.createClass({
</div> </div>
); );
} else { } else {
const myUserId = MatrixClientPeg.get().credentials.userId;
const myMember = this.state.room.getMember(myUserId);
const inviteEvent = myMember.events.member; const inviteEvent = myMember.events.member;
var inviterName = inviteEvent.sender ? inviteEvent.sender.name : inviteEvent.getSender(); var inviterName = inviteEvent.sender ? inviteEvent.sender.name : inviteEvent.getSender();
@ -1609,7 +1610,7 @@ module.exports = React.createClass({
} else if (this.state.showingPinned) { } else if (this.state.showingPinned) {
hideCancel = true; // has own cancel hideCancel = true; // has own cancel
aux = <PinnedEventsPanel room={this.state.room} onCancelClick={this.onPinnedClick} />; 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 do have a room object for this room, but we're not currently in it.
// We may have a 3rd party invite to it. // We may have a 3rd party invite to it.
var inviterName = undefined; var inviterName = undefined;
@ -1651,7 +1652,7 @@ module.exports = React.createClass({
let messageComposer, searchInfo; let messageComposer, searchInfo;
const canSpeak = ( const canSpeak = (
// joined and not showing search results // joined and not showing search results
myMember && (myMember.membership == 'join') && !this.state.searchResults myMembership == 'join' && !this.state.searchResults
); );
if (canSpeak) { if (canSpeak) {
messageComposer = messageComposer =
@ -1786,15 +1787,15 @@ module.exports = React.createClass({
oobData={this.props.oobData} oobData={this.props.oobData}
editing={this.state.editingRoomSettings} editing={this.state.editingRoomSettings}
saving={this.state.uploadingRoomSettings} saving={this.state.uploadingRoomSettings}
inRoom={myMember && myMember.membership === 'join'} inRoom={myMembership === 'join'}
collapsedRhs={this.props.collapsedRhs} collapsedRhs={this.props.collapsedRhs}
onSearchClick={this.onSearchClick} onSearchClick={this.onSearchClick}
onSettingsClick={this.onSettingsClick} onSettingsClick={this.onSettingsClick}
onPinnedClick={this.onPinnedClick} onPinnedClick={this.onPinnedClick}
onSaveClick={this.onSettingsSaveClick} onSaveClick={this.onSettingsSaveClick}
onCancelClick={(aux && !hideCancel) ? this.onCancelClick : null} onCancelClick={(aux && !hideCancel) ? this.onCancelClick : null}
onForgetClick={(myMember && myMember.membership === "leave") ? this.onForgetClick : null} onForgetClick={(myMembership === "leave") ? this.onForgetClick : null}
onLeaveClick={(myMember && myMember.membership === "join") ? this.onLeaveClick : null} onLeaveClick={(myMembership === "join") ? this.onLeaveClick : null}
/> />
{ auxPanel } { auxPanel }
<div className={fadableSectionClasses}> <div className={fadableSectionClasses}>

View file

@ -921,6 +921,25 @@ module.exports = React.createClass({
</div>; </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() { _renderClearCache: function() {
return <div> return <div>
<h3>{ _t("Clear Cache") }</h3> <h3>{ _t("Clear Cache") }</h3>
@ -1407,6 +1426,8 @@ module.exports = React.createClass({
{ this._renderDeactivateAccount() } { this._renderDeactivateAccount() }
{ this._renderTermsAndConditionsLinks() }
</GeminiScrollbarWrapper> </GeminiScrollbarWrapper>
</div> </div>
); );

View file

@ -19,6 +19,7 @@ import {ContentRepo} from "matrix-js-sdk";
import MatrixClientPeg from "../../../MatrixClientPeg"; import MatrixClientPeg from "../../../MatrixClientPeg";
import Modal from '../../../Modal'; import Modal from '../../../Modal';
import sdk from "../../../index"; import sdk from "../../../index";
import DMRoomMap from '../../../utils/DMRoomMap';
module.exports = React.createClass({ module.exports = React.createClass({
displayName: 'RoomAvatar', displayName: 'RoomAvatar',
@ -107,58 +108,37 @@ module.exports = React.createClass({
}, },
getOneToOneAvatar: function(props) { getOneToOneAvatar: function(props) {
if (!props.room) return null; const room = props.room;
if (!room) {
const mlist = props.room.currentState.members; return null;
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;
}
} }
let otherMember = null;
if (userIds.length == 2) { const otherUserId = DMRoomMap.shared().getUserIdForRoomId(room.roomId);
let theOtherGuy = null; if (otherUserId) {
if (mlist[userIds[0]].userId == MatrixClientPeg.get().credentials.userId) { otherMember = room.getMember(otherUserId);
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,
);
} else { } 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() { onRoomAvatarClick: function() {

View file

@ -346,20 +346,18 @@ module.exports = React.createClass({
}, },
render: function() { render: function() {
const myMember = this.props.room.getMember( const myMembership = this.props.room.getMyMembership();
MatrixClientPeg.get().credentials.userId,
);
// Can't set notif level or tags on non-join rooms // Can't set notif level or tags on non-join rooms
if (myMember.membership !== 'join') { if (myMembership !== 'join') {
return this._renderLeaveMenu(myMember.membership); return this._renderLeaveMenu(myMembership);
} }
return ( return (
<div> <div>
{ this._renderNotifMenu() } { this._renderNotifMenu() }
<hr className="mx_RoomTileContextMenu_separator" /> <hr className="mx_RoomTileContextMenu_separator" />
{ this._renderLeaveMenu(myMember.membership) } { this._renderLeaveMenu(myMembership) }
<hr className="mx_RoomTileContextMenu_separator" /> <hr className="mx_RoomTileContextMenu_separator" />
{ this._renderRoomTagMenu() } { this._renderRoomTagMenu() }
</div> </div>

View file

@ -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. // XXX: fragile as all hell - fixme somehow, perhaps with a dedicated Room.encryption event or something.
MatrixClientPeg.get().on("event", this.onEvent); MatrixClientPeg.get().on("event", this.onEvent);
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate); 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() { componentWillUnmount() {
@ -208,7 +225,6 @@ export default class MessageComposer extends React.Component {
} }
render() { render() {
const me = this.props.room.getMember(MatrixClientPeg.get().credentials.userId);
const uploadInputStyle = {display: 'none'}; const uploadInputStyle = {display: 'none'};
const MemberAvatar = sdk.getComponent('avatars.MemberAvatar'); const MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
const TintableSvg = sdk.getComponent("elements.TintableSvg"); const TintableSvg = sdk.getComponent("elements.TintableSvg");
@ -216,11 +232,13 @@ export default class MessageComposer extends React.Component {
const controls = []; const controls = [];
controls.push( if (this.state.me) {
<div key="controls_avatar" className="mx_MessageComposer_avatar"> controls.push(
<MemberAvatar member={me} width={24} height={24} /> <div key="controls_avatar" className="mx_MessageComposer_avatar">
</div>, <MemberAvatar member={this.state.me} width={24} height={24} />
); </div>,
);
}
let e2eImg, e2eTitle, e2eClass; let e2eImg, e2eTitle, e2eClass;
const roomIsEncrypted = MatrixClientPeg.get().isRoomEncrypted(this.props.room.roomId); const roomIsEncrypted = MatrixClientPeg.get().isRoomEncrypted(this.props.room.roomId);

View file

@ -97,7 +97,7 @@ module.exports = React.createClass({
}; };
// All rooms that should be kept in the room list when filtering. // All rooms that should be kept in the room list when filtering.
// By default, show all rooms. // 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 // Listen to updates to group data. RoomList cares about members and rooms in order
// to filter the room list when group tags are selected. // to filter the room list when group tags are selected.
@ -302,7 +302,7 @@ module.exports = React.createClass({
this._visibleRooms = Array.from(roomSet); this._visibleRooms = Array.from(roomSet);
} else { } else {
// Show all rooms // Show all rooms
this._visibleRooms = MatrixClientPeg.get().getRooms(); this._visibleRooms = MatrixClientPeg.get().getVisibleRooms();
} }
this._delayedRefreshRoomList(); this._delayedRefreshRoomList();
}, },

View file

@ -799,15 +799,15 @@ module.exports = React.createClass({
} }
let leaveButton = null; let leaveButton = null;
const myMember = this.props.room.getMember(myUserId); const myMemberShip = this.props.room.getMyMembership();
if (myMember) { if (myMemberShip) {
if (myMember.membership === "join") { if (myMemberShip === "join") {
leaveButton = ( leaveButton = (
<AccessibleButton className="mx_RoomSettings_leaveButton" onClick={this.onLeaveClick}> <AccessibleButton className="mx_RoomSettings_leaveButton" onClick={this.onLeaveClick}>
{ _t('Leave room') } { _t('Leave room') }
</AccessibleButton> </AccessibleButton>
); );
} else if (myMember.membership === "leave") { } else if (myMemberShip === "leave") {
leaveButton = ( leaveButton = (
<AccessibleButton className="mx_RoomSettings_leaveButton" onClick={this.onForgetClick}> <AccessibleButton className="mx_RoomSettings_leaveButton" onClick={this.onForgetClick}>
{ _t('Forget room') } { _t('Forget room') }

View file

@ -203,6 +203,8 @@
"Your browser does not support the required cryptography extensions": "Your browser does not support the required cryptography extensions", "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", "Not a valid Riot keyfile": "Not a valid Riot keyfile",
"Authentication check failed: incorrect password?": "Authentication check failed: incorrect password?", "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", "Failed to join room": "Failed to join room",
"Message Pinning": "Message Pinning", "Message Pinning": "Message Pinning",
"Increase performance by only loading room members on first view": "Increase performance by only loading room members on first view", "Increase performance by only loading room members on first view": "Increase performance by only loading room members on first view",
@ -1129,6 +1131,7 @@
"Lazy loading members not supported": "Lazy loading members not supported", "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.", "Lazy loading is not supported by your current homeserver.": "Lazy loading is not supported by your current homeserver.",
"Deactivate my account": "Deactivate my account", "Deactivate my account": "Deactivate my account",
"Legal": "Legal",
"Clear Cache": "Clear Cache", "Clear Cache": "Clear Cache",
"Clear Cache and Reload": "Clear Cache and Reload", "Clear Cache and Reload": "Clear Cache and Reload",
"Updates": "Updates", "Updates": "Updates",

View file

@ -284,8 +284,8 @@ class RoomListStore extends Store {
if (optimisticRequest && roomB === optimisticRequest.room) metaB = optimisticRequest.metaData; 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 // Make sure the room tag has an order element, if not set it to be the bottom
const a = metaA.order; const a = metaA ? metaA.order : undefined;
const b = metaB.order; const b = metaB ? metaB.order : undefined;
// Order undefined room tag orders to the bottom // Order undefined room tag orders to the bottom
if (a === undefined && b !== undefined) { if (a === undefined && b !== undefined) {

View file

@ -223,7 +223,13 @@ class RoomViewStore extends Store {
action: 'join_room_error', action: 'join_room_error',
err: err, 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"); const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createTrackedDialog('Failed to join room', '', ErrorDialog, { Modal.createTrackedDialog('Failed to join room', '', ErrorDialog, {
title: _t("Failed to join room"), title: _t("Failed to join room"),

View file

@ -94,6 +94,7 @@ describe('RoomList', () => {
createRoom({tags: {'m.lowpriority': {}}, name: 'Some unimportant room'}), createRoom({tags: {'m.lowpriority': {}}, name: 'Some unimportant room'}),
createRoom({tags: {'custom.tag': {}}, name: 'Some room customly tagged'}), createRoom({tags: {'custom.tag': {}}, name: 'Some room customly tagged'}),
]; ];
client.getVisibleRooms = client.getRooms;
const roomMap = {}; const roomMap = {};
client.getRooms().forEach((r) => { client.getRooms().forEach((r) => {

View file

@ -74,6 +74,7 @@ export function createTestClient() {
getPushActionsForEvent: sinon.stub(), getPushActionsForEvent: sinon.stub(),
getRoom: sinon.stub().returns(mkStubRoom()), getRoom: sinon.stub().returns(mkStubRoom()),
getRooms: sinon.stub().returns([]), getRooms: sinon.stub().returns([]),
getVisibleRooms: sinon.stub().returns([]),
getGroups: sinon.stub().returns([]), getGroups: sinon.stub().returns([]),
loginFlows: sinon.stub(), loginFlows: sinon.stub(),
on: sinon.stub(), on: sinon.stub(),
@ -257,6 +258,7 @@ export function mkStubRoom(roomId = null) {
hasMembershipState: () => null, hasMembershipState: () => null,
getVersion: () => '1', getVersion: () => '1',
shouldUpgradeToVersion: () => null, shouldUpgradeToVersion: () => null,
getMyMembership: () => "join",
currentState: { currentState: {
getStateEvents: sinon.stub(), getStateEvents: sinon.stub(),
mayClientSendStateEvent: sinon.stub().returns(true), mayClientSendStateEvent: sinon.stub().returns(true),