Merge pull request #102 from matrix-org/matthew/roompreview
Try to support non-guest room peek.
This commit is contained in:
commit
41da05f36a
10 changed files with 229 additions and 121 deletions
|
@ -63,6 +63,7 @@ var cssAttrs = [
|
|||
"backgroundColor",
|
||||
"borderColor",
|
||||
"borderTopColor",
|
||||
"borderBottomColor",
|
||||
];
|
||||
|
||||
var svgAttrs = [
|
||||
|
|
|
@ -65,6 +65,7 @@ module.exports = React.createClass({
|
|||
collapse_rhs: false,
|
||||
ready: false,
|
||||
width: 10000,
|
||||
autoPeek: true, // by default, we peek into rooms when we try to join them
|
||||
};
|
||||
if (s.logged_in) {
|
||||
if (MatrixClientPeg.get().getRooms().length) {
|
||||
|
@ -304,6 +305,9 @@ module.exports = React.createClass({
|
|||
});
|
||||
break;
|
||||
case 'view_room':
|
||||
// by default we autoPeek rooms, unless we were called explicitly with
|
||||
// autoPeek=false by something like RoomDirectory who has already peeked
|
||||
this.setState({ autoPeek : payload.auto_peek === false ? false : true });
|
||||
this._viewRoom(payload.room_id, payload.show_settings);
|
||||
break;
|
||||
case 'view_prev_room':
|
||||
|
@ -787,6 +791,7 @@ module.exports = React.createClass({
|
|||
<RoomView
|
||||
ref="roomView"
|
||||
roomId={this.state.currentRoom}
|
||||
autoPeek={this.state.autoPeek}
|
||||
key={this.state.currentRoom}
|
||||
ConferenceHandler={this.props.ConferenceHandler} />
|
||||
);
|
||||
|
|
|
@ -57,7 +57,9 @@ if (DEBUG_SCROLL) {
|
|||
module.exports = React.createClass({
|
||||
displayName: 'RoomView',
|
||||
propTypes: {
|
||||
ConferenceHandler: React.PropTypes.any
|
||||
ConferenceHandler: React.PropTypes.any,
|
||||
roomId: React.PropTypes.string,
|
||||
autoPeek: React.PropTypes.bool, // should we try to peek the room on mount, or has whoever invoked us already initiated a peek?
|
||||
},
|
||||
|
||||
/* properties in RoomView objects include:
|
||||
|
@ -78,7 +80,9 @@ module.exports = React.createClass({
|
|||
syncState: MatrixClientPeg.get().getSyncState(),
|
||||
hasUnsentMessages: this._hasUnsentMessages(room),
|
||||
callState: null,
|
||||
autoPeekDone: false, // track whether our autoPeek (if any) has completed)
|
||||
guestsCanJoin: false,
|
||||
canPeek: false,
|
||||
readMarkerEventId: room ? room.getEventReadUpTo(MatrixClientPeg.get().credentials.userId) : null,
|
||||
readMarkerGhostEventId: undefined
|
||||
}
|
||||
|
@ -86,6 +90,7 @@ module.exports = React.createClass({
|
|||
|
||||
componentWillMount: function() {
|
||||
this.dispatcherRef = dis.register(this.onAction);
|
||||
MatrixClientPeg.get().on("Room", this.onNewRoom);
|
||||
MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline);
|
||||
MatrixClientPeg.get().on("Room.name", this.onRoomName);
|
||||
MatrixClientPeg.get().on("Room.accountData", this.onRoomAccountData);
|
||||
|
@ -111,27 +116,21 @@ module.exports = React.createClass({
|
|||
// We can /peek though. If it fails then we present the join UI. If it
|
||||
// succeeds then great, show the preview (but we still may be able to /join!).
|
||||
if (!this.state.room) {
|
||||
if (this.props.autoPeek) {
|
||||
console.log("Attempting to peek into room %s", this.props.roomId);
|
||||
MatrixClientPeg.get().peekInRoom(this.props.roomId).done(() => {
|
||||
// we don't need to do anything - JS SDK will emit Room events
|
||||
// which will update the UI. We *do* however need to know if we
|
||||
// can join the room so we can fiddle with the UI appropriately.
|
||||
var peekedRoom = MatrixClientPeg.get().getRoom(this.props.roomId);
|
||||
if (!peekedRoom) {
|
||||
return;
|
||||
}
|
||||
var guestAccessEvent = peekedRoom.currentState.getStateEvents("m.room.guest_access", "");
|
||||
if (!guestAccessEvent) {
|
||||
return;
|
||||
}
|
||||
if (guestAccessEvent.getContent().guest_access === "can_join") {
|
||||
this.setState({
|
||||
guestsCanJoin: true
|
||||
});
|
||||
}
|
||||
}, function(err) {
|
||||
MatrixClientPeg.get().peekInRoom(this.props.roomId).catch((err) => {
|
||||
console.error("Failed to peek into room: %s", err);
|
||||
}).finally(() => {
|
||||
// we don't need to do anything - JS SDK will emit Room events
|
||||
// which will update the UI.
|
||||
this.setState({
|
||||
autoPeekDone: true
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
this._calculatePeekRules(this.state.room);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -155,6 +154,7 @@ module.exports = React.createClass({
|
|||
}
|
||||
dis.unregister(this.dispatcherRef);
|
||||
if (MatrixClientPeg.get()) {
|
||||
MatrixClientPeg.get().removeListener("Room", this.onNewRoom);
|
||||
MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline);
|
||||
MatrixClientPeg.get().removeListener("Room.name", this.onRoomName);
|
||||
MatrixClientPeg.get().removeListener("Room.accountData", this.onRoomAccountData);
|
||||
|
@ -278,6 +278,32 @@ module.exports = React.createClass({
|
|||
});
|
||||
},
|
||||
|
||||
onNewRoom: function(room) {
|
||||
if (room.roomId == this.props.roomId) {
|
||||
this.setState({
|
||||
room: room
|
||||
});
|
||||
}
|
||||
|
||||
this._calculatePeekRules(room);
|
||||
},
|
||||
|
||||
_calculatePeekRules: function(room) {
|
||||
var guestAccessEvent = room.currentState.getStateEvents("m.room.guest_access", "");
|
||||
if (guestAccessEvent && guestAccessEvent.getContent().guest_access === "can_join") {
|
||||
this.setState({
|
||||
guestsCanJoin: true
|
||||
});
|
||||
}
|
||||
|
||||
var historyVisibility = room.currentState.getStateEvents("m.room.history_visibility", "");
|
||||
if (historyVisibility && historyVisibility.getContent().history_visibility === "world_readable") {
|
||||
this.setState({
|
||||
canPeek: true
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
onRoomName: function(room) {
|
||||
if (room.roomId == this.props.roomId) {
|
||||
this.setState({
|
||||
|
@ -349,6 +375,14 @@ module.exports = React.createClass({
|
|||
if (member.roomId === this.props.roomId) {
|
||||
// a member state changed in this room, refresh the tab complete list
|
||||
this._updateTabCompleteList(this.state.room);
|
||||
|
||||
var room = MatrixClientPeg.get().getRoom(this.props.roomId);
|
||||
var me = MatrixClientPeg.get().credentials.userId;
|
||||
if (this.state.joining && room.hasMembershipState(me, "join")) {
|
||||
this.setState({
|
||||
joining: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.props.ConferenceHandler) {
|
||||
|
@ -522,10 +556,17 @@ module.exports = React.createClass({
|
|||
|
||||
onJoinButtonClicked: function(ev) {
|
||||
var self = this;
|
||||
MatrixClientPeg.get().joinRoom(this.props.roomId).then(function() {
|
||||
MatrixClientPeg.get().joinRoom(this.props.roomId).done(function() {
|
||||
// It is possible that there is no Room yet if state hasn't come down
|
||||
// from /sync - joinRoom will resolve when the HTTP request to join succeeds,
|
||||
// NOT when it comes down /sync. If there is no room, we'll keep the
|
||||
// joining flag set until we see it. Likewise, if our state is not
|
||||
// "join" we'll keep this flag set until it comes down /sync.
|
||||
var room = MatrixClientPeg.get().getRoom(self.props.roomId);
|
||||
var me = MatrixClientPeg.get().credentials.userId;
|
||||
self.setState({
|
||||
joining: false,
|
||||
room: MatrixClientPeg.get().getRoom(self.props.roomId)
|
||||
joining: room ? !room.hasMembershipState(me, "join") : true,
|
||||
room: room
|
||||
});
|
||||
}, function(error) {
|
||||
self.setState({
|
||||
|
@ -929,17 +970,38 @@ module.exports = React.createClass({
|
|||
);
|
||||
}
|
||||
|
||||
var visibilityDeferred;
|
||||
if (old_history_visibility != newVals.history_visibility &&
|
||||
newVals.history_visibility != undefined) {
|
||||
deferreds.push(
|
||||
visibilityDeferred =
|
||||
MatrixClientPeg.get().sendStateEvent(
|
||||
this.state.room.roomId, "m.room.history_visibility", {
|
||||
history_visibility: newVals.history_visibility,
|
||||
}, ""
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (old_guest_read != newVals.guest_read ||
|
||||
old_guest_join != newVals.guest_join)
|
||||
{
|
||||
var guestDeferred =
|
||||
MatrixClientPeg.get().setGuestAccess(this.state.room.roomId, {
|
||||
allowRead: newVals.guest_read,
|
||||
allowJoin: newVals.guest_join
|
||||
});
|
||||
|
||||
if (visibilityDeferred) {
|
||||
visibilityDeferred = visibilityDeferred.then(guestDeferred);
|
||||
}
|
||||
else {
|
||||
visibilityDeferred = guestDeferred;
|
||||
}
|
||||
}
|
||||
|
||||
if (visibilityDeferred) {
|
||||
deferreds.push(visibilityDeferred);
|
||||
}
|
||||
|
||||
// setRoomMutePushRule will do nothing if there is no change
|
||||
deferreds.push(
|
||||
MatrixClientPeg.get().setRoomMutePushRule(
|
||||
|
@ -1040,17 +1102,6 @@ module.exports = React.createClass({
|
|||
);
|
||||
}
|
||||
|
||||
if (old_guest_read != newVals.guest_read ||
|
||||
old_guest_join != newVals.guest_join)
|
||||
{
|
||||
deferreds.push(
|
||||
MatrixClientPeg.get().setGuestAccess(this.state.room.roomId, {
|
||||
allowRead: newVals.guest_read,
|
||||
allowJoin: newVals.guest_join
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (deferreds.length) {
|
||||
var self = this;
|
||||
q.allSettled(deferreds).then(
|
||||
|
@ -1399,12 +1450,30 @@ module.exports = React.createClass({
|
|||
|
||||
if (!this.state.room) {
|
||||
if (this.props.roomId) {
|
||||
if (this.props.autoPeek && !this.state.autoPeekDone) {
|
||||
var Loader = sdk.getComponent("elements.Spinner");
|
||||
return (
|
||||
<div>
|
||||
<button onClick={this.onJoinButtonClicked}>Join Room</button>
|
||||
<div className="mx_RoomView">
|
||||
<Loader />
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
var joinErrorText = this.state.joinError ? "Failed to join room!" : "";
|
||||
return (
|
||||
<div className="mx_RoomView">
|
||||
<RoomHeader ref="header" room={this.state.room} simpleHeader="Join room"/>
|
||||
<div className="mx_RoomView_auxPanel">
|
||||
<RoomPreviewBar onJoinClick={ this.onJoinButtonClicked }
|
||||
canJoin={ true } canPreview={ false }/>
|
||||
<div className="error">{joinErrorText}</div>
|
||||
</div>
|
||||
<div className="mx_RoomView_messagePanel"></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return (
|
||||
<div />
|
||||
);
|
||||
|
@ -1425,19 +1494,26 @@ module.exports = React.createClass({
|
|||
var inviteEvent = myMember.events.member;
|
||||
var inviterName = inviteEvent.sender ? inviteEvent.sender.name : inviteEvent.getSender();
|
||||
// XXX: Leaving this intentionally basic for now because invites are about to change totally
|
||||
// FIXME: This comment is now outdated - what do we need to fix? ^
|
||||
var joinErrorText = this.state.joinError ? "Failed to join room!" : "";
|
||||
var rejectErrorText = this.state.rejectError ? "Failed to reject invite!" : "";
|
||||
|
||||
// We deliberately don't try to peek into invites, even if we have permission to peek
|
||||
// as they could be a spam vector.
|
||||
// XXX: in future we could give the option of a 'Preview' button which lets them view anyway.
|
||||
|
||||
return (
|
||||
<div className="mx_RoomView">
|
||||
<RoomHeader ref="header" room={this.state.room} simpleHeader="Room invite"/>
|
||||
<div className="mx_RoomView_invitePrompt">
|
||||
<div>{inviterName} has invited you to a room</div>
|
||||
<br/>
|
||||
<button ref="joinButton" onClick={this.onJoinButtonClicked}>Join</button>
|
||||
<button onClick={this.onRejectButtonClicked}>Reject</button>
|
||||
<div className="mx_RoomView_auxPanel">
|
||||
<RoomPreviewBar onJoinClick={ this.onJoinButtonClicked }
|
||||
onRejectClick={ this.onRejectButtonClicked }
|
||||
inviterName={ inviterName }
|
||||
canJoin={ true } canPreview={ false }/>
|
||||
<div className="error">{joinErrorText}</div>
|
||||
<div className="error">{rejectErrorText}</div>
|
||||
</div>
|
||||
<div className="mx_RoomView_messagePanel"></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1552,6 +1628,12 @@ module.exports = React.createClass({
|
|||
<RoomPreviewBar onJoinClick={this.onJoinButtonClicked} canJoin={true} />
|
||||
);
|
||||
}
|
||||
else if (this.state.canPeek &&
|
||||
(!myMember || myMember.membership !== "join")) {
|
||||
aux = (
|
||||
<RoomPreviewBar onJoinClick={this.onJoinButtonClicked} canJoin={true} />
|
||||
);
|
||||
}
|
||||
|
||||
var conferenceCallNotification = null;
|
||||
if (this.state.displayConfCallNotification) {
|
||||
|
|
|
@ -306,7 +306,7 @@ module.exports = React.createClass({
|
|||
rowClassName="mx_UserSettings_profileTableRow"
|
||||
rowLabelClassName="mx_UserSettings_profileLabelCell"
|
||||
rowInputClassName="mx_UserSettings_profileInputCell"
|
||||
buttonClassName="mx_UserSettings_button"
|
||||
buttonClassName="mx_UserSettings_button mx_UserSettings_changePasswordButton"
|
||||
onError={this.onPasswordChangeError}
|
||||
onFinished={this.onPasswordChanged} />
|
||||
);
|
||||
|
|
|
@ -72,7 +72,7 @@ module.exports = React.createClass({
|
|||
},
|
||||
|
||||
render: function() {
|
||||
var presenceClass = PRESENCE_CLASS[this.props.presenceState];
|
||||
var presenceClass = PRESENCE_CLASS[this.props.presenceState] || "mx_EntityTile_offline";
|
||||
var mainClassName = "mx_EntityTile ";
|
||||
mainClassName += presenceClass;
|
||||
if (this.state.hover) {
|
||||
|
@ -129,9 +129,9 @@ module.exports = React.createClass({
|
|||
onMouseLeave={ this.mouseLeave }>
|
||||
<div className="mx_EntityTile_avatar">
|
||||
{ av }
|
||||
{ power }
|
||||
</div>
|
||||
{ nameEl }
|
||||
{ power }
|
||||
{ inviteButton }
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -362,7 +362,7 @@ module.exports = React.createClass({
|
|||
invitedSection = (
|
||||
<div className="mx_MemberList_invited">
|
||||
<h2>Invited</h2>
|
||||
<div className="mx_MemberList_wrapper">
|
||||
<div autoshow={true} className="mx_MemberList_wrapper">
|
||||
{invitedMemberTiles}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -370,15 +370,15 @@ module.exports = React.createClass({
|
|||
}
|
||||
return (
|
||||
<div className="mx_MemberList">
|
||||
<GeminiScrollbar autoshow={true} className="mx_MemberList_border">
|
||||
{this.inviteTile()}
|
||||
<div>
|
||||
<GeminiScrollbar autoshow={true} className="mx_MemberList_joined mx_MemberList_outerWrapper">
|
||||
<div className="mx_MemberList_wrapper">
|
||||
{this.makeMemberTiles('join', this.state.searchQuery)}
|
||||
</div>
|
||||
</div>
|
||||
{invitedSection}
|
||||
</GeminiScrollbar>
|
||||
<div className="mx_MemberList_bottom">
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -23,33 +23,60 @@ module.exports = React.createClass({
|
|||
|
||||
propTypes: {
|
||||
onJoinClick: React.PropTypes.func,
|
||||
canJoin: React.PropTypes.bool
|
||||
onRejectClick: React.PropTypes.func,
|
||||
inviterName: React.PropTypes.string,
|
||||
canJoin: React.PropTypes.bool,
|
||||
canPreview: React.PropTypes.bool,
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
onJoinClick: function() {},
|
||||
canJoin: false
|
||||
canJoin: false,
|
||||
canPreview: true,
|
||||
};
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var joinBlock;
|
||||
var joinBlock, previewBlock;
|
||||
|
||||
if (this.props.canJoin) {
|
||||
if (this.props.inviterName) {
|
||||
joinBlock = (
|
||||
<div>
|
||||
<div className="mx_RoomPreviewBar_invite_text">
|
||||
You have been invited to join this room by { this.props.inviterName }
|
||||
</div>
|
||||
<div className="mx_RoomPreviewBar_join_text">
|
||||
Would you like to <a onClick={ this.props.onJoinClick }>accept</a> or <a onClick={ this.props.onRejectClick }>decline</a> this invitation?
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
}
|
||||
else if (this.props.canJoin) {
|
||||
joinBlock = (
|
||||
<div>
|
||||
<div className="mx_RoomPreviewBar_join_text">
|
||||
Would you like to <a onClick={ this.props.onJoinClick }>join</a> this room?
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.props.canPreview) {
|
||||
previewBlock = (
|
||||
<div className="mx_RoomPreviewBar_preview_text">
|
||||
This is a preview of this room. Room interactions have been disabled.
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx_RoomPreviewBar">
|
||||
<div className="mx_RoomPreviewBar_preview_text">
|
||||
This is a preview of this room. Room interactions have been disabled.
|
||||
</div>
|
||||
<div className="mx_RoomPreviewBar_wrapper">
|
||||
{ joinBlock }
|
||||
{ previewBlock }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -295,8 +295,8 @@ module.exports = React.createClass({
|
|||
else {
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Invalid alias format",
|
||||
description: "'" + alias + "' is not a valid format for an alias",
|
||||
title: "Invalid address format",
|
||||
description: "'" + alias + "' is not a valid format for an address",
|
||||
});
|
||||
}
|
||||
},
|
||||
|
@ -482,11 +482,11 @@ module.exports = React.createClass({
|
|||
remote_aliases_section =
|
||||
<div>
|
||||
<div className="mx_RoomSettings_aliasLabel">
|
||||
This room can be found elsewhere as:
|
||||
Remote addresses for this room:
|
||||
</div>
|
||||
<div className="mx_RoomSettings_aliasesTable">
|
||||
{ remote_domains.map(function(state_key, i) {
|
||||
self.state.aliases[state_key].map(function(alias, j) {
|
||||
return self.state.aliases[state_key].map(function(alias, j) {
|
||||
return (
|
||||
<div className="mx_RoomSettings_aliasesTableRow" key={ i + "_" + j }>
|
||||
<EditableText
|
||||
|
@ -494,8 +494,6 @@ module.exports = React.createClass({
|
|||
blurToCancel={ false }
|
||||
editable={ false }
|
||||
initialValue={ alias } />
|
||||
<div className="mx_RoomSettings_deleteAlias">
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
@ -513,7 +511,7 @@ module.exports = React.createClass({
|
|||
return <option value={ alias } key={ i + "_" + j }>{ alias }</option>
|
||||
});
|
||||
})}
|
||||
<option value="" key="unset">not set</option>
|
||||
<option value="" key="unset">not specified</option>
|
||||
</select>
|
||||
}
|
||||
else {
|
||||
|
@ -522,24 +520,26 @@ module.exports = React.createClass({
|
|||
|
||||
var aliases_section =
|
||||
<div>
|
||||
<h3>Directory</h3>
|
||||
<h3>Addresses</h3>
|
||||
<div className="mx_RoomSettings_aliasLabel">The main address for this room is: { canonical_alias_section }</div>
|
||||
<div className="mx_RoomSettings_aliasLabel">
|
||||
{ this.state.aliases[domain].length
|
||||
? "This room can be found on " + domain + " as:"
|
||||
: "This room is not findable on " + domain }
|
||||
? "Local addresses for this room:"
|
||||
: "This room has no local addresses" }
|
||||
</div>
|
||||
<div className="mx_RoomSettings_aliasesTable">
|
||||
{ this.state.aliases[domain].map(function(alias, i) {
|
||||
var deleteButton;
|
||||
if (can_set_room_aliases) {
|
||||
deleteButton = <img src="img/cancel-small.svg" width="14" height="14" alt="Delete" onClick={ self.onAliasDeleted.bind(self, domain, i) }/>;
|
||||
deleteButton = <img src="img/cancel-small.svg" width="14" height="14" alt="Delete"
|
||||
onClick={ self.onAliasDeleted.bind(self, domain, i) }/>;
|
||||
}
|
||||
return (
|
||||
<div className="mx_RoomSettings_aliasesTableRow" key={ i }>
|
||||
<EditableText
|
||||
className="mx_RoomSettings_alias mx_RoomSettings_editable"
|
||||
placeholderClassName="mx_RoomSettings_aliasPlaceholder"
|
||||
placeholder={ "New alias (e.g. #foo:" + domain + ")" }
|
||||
placeholder={ "New address (e.g. #foo:" + domain + ")" }
|
||||
blurToCancel={ false }
|
||||
onValueChanged={ self.onAliasChanged.bind(self, domain, i) }
|
||||
editable={ can_set_room_aliases }
|
||||
|
@ -556,18 +556,18 @@ module.exports = React.createClass({
|
|||
ref="add_alias"
|
||||
className="mx_RoomSettings_alias mx_RoomSettings_editable"
|
||||
placeholderClassName="mx_RoomSettings_aliasPlaceholder"
|
||||
placeholder={ "New alias (e.g. #foo:" + domain + ")" }
|
||||
placeholder={ "New address (e.g. #foo:" + domain + ")" }
|
||||
blurToCancel={ false }
|
||||
onValueChanged={ self.onAliasAdded } />
|
||||
<div className="mx_RoomSettings_addAlias">
|
||||
<img src="img/plus.svg" width="14" height="14" alt="Add" onClick={ self.onAliasAdded.bind(self, undefined) }/>
|
||||
<img src="img/plus.svg" width="14" height="14" alt="Add"
|
||||
onClick={ self.onAliasAdded.bind(self, undefined) }/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{ remote_aliases_section }
|
||||
|
||||
<div className="mx_RoomSettings_aliasLabel">The official way to refer to this room is: { canonical_alias_section }</div>
|
||||
</div>;
|
||||
|
||||
var room_colors_section =
|
||||
|
@ -597,23 +597,17 @@ module.exports = React.createClass({
|
|||
</div>;
|
||||
|
||||
var user_levels_section;
|
||||
if (user_levels.length) {
|
||||
if (Object.keys(user_levels).length) {
|
||||
user_levels_section =
|
||||
<div>
|
||||
<div>
|
||||
Users with specific roles are:
|
||||
</div>
|
||||
<div>
|
||||
<ul>
|
||||
{Object.keys(user_levels).map(function(user, i) {
|
||||
return (
|
||||
<div className="mx_RoomSettings_userLevel" key={user}>
|
||||
{ user } is a
|
||||
<PowerSelector value={ user_levels[user] } disabled={true}/>
|
||||
</div>
|
||||
<li className="mx_RoomSettings_userLevel" key={user}>
|
||||
{ user } is a <PowerSelector value={ user_levels[user] } disabled={true}/>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>;
|
||||
</ul>;
|
||||
}
|
||||
else {
|
||||
user_levels_section = <div>No users have specific privileges in this room.</div>
|
||||
|
@ -659,7 +653,7 @@ module.exports = React.createClass({
|
|||
|
||||
var tags_section =
|
||||
<div className="mx_RoomSettings_tags">
|
||||
This room is tagged as
|
||||
Tagged as:
|
||||
{ can_set_tag ?
|
||||
tags.map(function(tag, i) {
|
||||
return (<label key={ i }>
|
||||
|
@ -673,25 +667,26 @@ module.exports = React.createClass({
|
|||
}
|
||||
</div>
|
||||
|
||||
// FIXME: disable guests_read if the user hasn't turned on shared history
|
||||
return (
|
||||
<div className="mx_RoomSettings">
|
||||
<label><input type="checkbox" ref="is_private" defaultChecked={join_rule != "public"}/> Make this room private</label> <br/>
|
||||
<label><input type="checkbox" ref="share_history" defaultChecked={history_visibility == "shared"}/> Share message history with new users</label> <br/>
|
||||
<label><input type="checkbox" ref="guests_read" defaultChecked={history_visibility === "world_readable"}/> Allow guests to read messages in this room</label> <br/>
|
||||
<label><input type="checkbox" ref="guests_join" defaultChecked={guest_access === "can_join"}/> Allow guests to join this room</label> <br/>
|
||||
<label className="mx_RoomSettings_encrypt"><input type="checkbox" /> Encrypt room</label>
|
||||
|
||||
{ tags_section }
|
||||
|
||||
<div className="mx_RoomSettings_toggles">
|
||||
<label><input type="checkbox" ref="are_notifications_muted" defaultChecked={are_notifications_muted}/> Mute notifications for this room</label>
|
||||
<label><input type="checkbox" ref="is_private" defaultChecked={join_rule != "public"}/> Make this room private</label>
|
||||
<label><input type="checkbox" ref="share_history" defaultChecked={history_visibility === "shared" || history_visibility === "world_readable"}/> Share message history with new participants</label>
|
||||
<label><input type="checkbox" ref="guests_join" defaultChecked={guest_access === "can_join"}/> Let guests join this room</label>
|
||||
<label><input type="checkbox" ref="guests_read" defaultChecked={history_visibility === "world_readable"}/> Let users read message history without joining</label>
|
||||
<label className="mx_RoomSettings_encrypt"><input type="checkbox" /> Encrypt room</label>
|
||||
</div>
|
||||
|
||||
|
||||
{ room_colors_section }
|
||||
|
||||
{ aliases_section }
|
||||
|
||||
<h3>Notifications</h3>
|
||||
<div className="mx_RoomSettings_settings">
|
||||
<label><input type="checkbox" ref="are_notifications_muted" defaultChecked={are_notifications_muted}/> Mute notifications for this room</label>
|
||||
</div>
|
||||
|
||||
<h3>Permissions</h3>
|
||||
<div className="mx_RoomSettings_powerLevels mx_RoomSettings_settings">
|
||||
<div className="mx_RoomSettings_powerLevel">
|
||||
|
@ -735,12 +730,8 @@ module.exports = React.createClass({
|
|||
{ unfederatable_section }
|
||||
</div>
|
||||
|
||||
<h3>Users</h3>
|
||||
<h3>Privileged Users</h3>
|
||||
<div className="mx_RoomSettings_userLevels mx_RoomSettings_settings">
|
||||
<div>
|
||||
Your role in this room is currently <b><PowerSelector room={ this.props.room } value={current_user_level} disabled={true}/></b>.
|
||||
</div>
|
||||
|
||||
{ user_levels_section }
|
||||
</div>
|
||||
|
||||
|
|
|
@ -104,13 +104,16 @@ var SearchableEntityList = React.createClass({
|
|||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={ "mx_SearchableEntityList " + (this.state.results.length ? "mx_SearchableEntityList_expanded" : "") }>
|
||||
{inputBox}
|
||||
<div className="mx_SearchableEntityList_list">
|
||||
<GeminiScrollbar className="mx_SearchableEntityList_listWrapper">
|
||||
<div autoshow={true} className="mx_SearchableEntityList_list">
|
||||
{this.state.results.map((entity) => {
|
||||
return entity.getJsx();
|
||||
})}
|
||||
</div>
|
||||
</GeminiScrollbar>
|
||||
{ this.state.results.length ? <div className="mx_SearchableEntityList_hrWrapper"><hr/></div> : '' }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -122,8 +122,7 @@ module.exports = React.createClass({
|
|||
height: this.props.height,
|
||||
objectFit: 'cover',
|
||||
};
|
||||
// FIXME: surely we should be using MemberAvatar or UserAvatar or something here...
|
||||
avatarImg = <img className="mx_RoomAvatar" src={this.state.avatarUrl} style={style} />;
|
||||
avatarImg = <img className="mx_BaseAvatar_image" src={this.state.avatarUrl} style={style} />;
|
||||
}
|
||||
|
||||
var uploadSection;
|
||||
|
|
Loading…
Reference in a new issue