Merge pull request #62 from matrix-org/kegan/archived-rooms
Show archived rooms and implement forgetting
This commit is contained in:
commit
e57d0601b6
3 changed files with 119 additions and 17 deletions
|
@ -875,7 +875,19 @@ module.exports = React.createClass({
|
||||||
action: 'leave_room',
|
action: 'leave_room',
|
||||||
room_id: this.props.roomId,
|
room_id: this.props.roomId,
|
||||||
});
|
});
|
||||||
this.props.onFinished();
|
},
|
||||||
|
|
||||||
|
onForgetClick: function() {
|
||||||
|
MatrixClientPeg.get().forget(this.props.roomId).done(function() {
|
||||||
|
dis.dispatch({ action: 'view_next_room' });
|
||||||
|
}, function(err) {
|
||||||
|
var errCode = err.errcode || "unknown error code";
|
||||||
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
|
Modal.createDialog(ErrorDialog, {
|
||||||
|
title: "Error",
|
||||||
|
description: `Failed to forget room (${errCode})`
|
||||||
|
});
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onRejectButtonClicked: function(ev) {
|
onRejectButtonClicked: function(ev) {
|
||||||
|
@ -1267,16 +1279,23 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
|
|
||||||
var messageComposer, searchInfo;
|
var messageComposer, searchInfo;
|
||||||
if (!this.state.searchResults) {
|
var canSpeak = (
|
||||||
|
// joined and not showing search results
|
||||||
|
myMember && (myMember.membership == 'join') && !this.state.searchResults
|
||||||
|
);
|
||||||
|
if (canSpeak) {
|
||||||
messageComposer =
|
messageComposer =
|
||||||
<MessageComposer room={this.state.room} roomView={this} uploadFile={this.uploadFile} callState={this.state.callState} />
|
<MessageComposer room={this.state.room} roomView={this} uploadFile={this.uploadFile} callState={this.state.callState} />
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
|
// TODO: Why aren't we storing the term/scope/count in this format
|
||||||
|
// in this.state if this is what RoomHeader desires?
|
||||||
|
if (this.state.searchResults) {
|
||||||
searchInfo = {
|
searchInfo = {
|
||||||
searchTerm : this.state.searchTerm,
|
searchTerm : this.state.searchTerm,
|
||||||
searchScope : this.state.searchScope,
|
searchScope : this.state.searchScope,
|
||||||
searchCount : this.state.searchCount,
|
searchCount : this.state.searchCount,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var call = CallHandler.getCallForRoom(this.props.roomId);
|
var call = CallHandler.getCallForRoom(this.props.roomId);
|
||||||
|
@ -1323,8 +1342,18 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ "mx_RoomView" + (inCall ? " mx_RoomView_inCall" : "") }>
|
<div className={ "mx_RoomView" + (inCall ? " mx_RoomView_inCall" : "") }>
|
||||||
<RoomHeader ref="header" room={this.state.room} searchInfo={searchInfo} editing={this.state.editingRoomSettings} onSearchClick={this.onSearchClick}
|
<RoomHeader ref="header" room={this.state.room} searchInfo={searchInfo}
|
||||||
onSettingsClick={this.onSettingsClick} onSaveClick={this.onSaveClick} onCancelClick={this.onCancelClick} onLeaveClick={this.onLeaveClick} />
|
editing={this.state.editingRoomSettings}
|
||||||
|
onSearchClick={this.onSearchClick}
|
||||||
|
onSettingsClick={this.onSettingsClick}
|
||||||
|
onSaveClick={this.onSaveClick}
|
||||||
|
onCancelClick={this.onCancelClick}
|
||||||
|
onForgetClick={
|
||||||
|
(myMember && myMember.membership === "leave") ? this.onForgetClick : null
|
||||||
|
}
|
||||||
|
onLeaveClick={
|
||||||
|
(myMember && myMember.membership === "join") ? this.onLeaveClick : null
|
||||||
|
} />
|
||||||
{ fileDropTarget }
|
{ fileDropTarget }
|
||||||
<div className="mx_RoomView_auxPanel">
|
<div className="mx_RoomView_auxPanel">
|
||||||
<CallView ref="callView" room={this.state.room} ConferenceHandler={this.props.ConferenceHandler}/>
|
<CallView ref="callView" room={this.state.room} ConferenceHandler={this.props.ConferenceHandler}/>
|
||||||
|
|
|
@ -131,7 +131,17 @@ module.exports = React.createClass({
|
||||||
if (this.props.onLeaveClick) {
|
if (this.props.onLeaveClick) {
|
||||||
leave_button =
|
leave_button =
|
||||||
<div className="mx_RoomHeader_button mx_RoomHeader_leaveButton">
|
<div className="mx_RoomHeader_button mx_RoomHeader_leaveButton">
|
||||||
<img src="img/leave.svg" title="Leave room" alt="Leave room" width="26" height="20" onClick={this.props.onLeaveClick}/>
|
<img src="img/leave.svg" title="Leave room" alt="Leave room"
|
||||||
|
width="26" height="20" onClick={this.props.onLeaveClick}/>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
var forget_button;
|
||||||
|
if (this.props.onForgetClick) {
|
||||||
|
forget_button =
|
||||||
|
<div className="mx_RoomHeader_button mx_RoomHeader_leaveButton">
|
||||||
|
<img src="img/leave.svg" title="Forget room" alt="Forget room"
|
||||||
|
width="26" height="20" onClick={this.props.onForgetClick}/>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,6 +159,7 @@ module.exports = React.createClass({
|
||||||
{cancel_button}
|
{cancel_button}
|
||||||
{save_button}
|
{save_button}
|
||||||
<div className="mx_RoomHeader_rightRow">
|
<div className="mx_RoomHeader_rightRow">
|
||||||
|
{ forget_button }
|
||||||
{ leave_button }
|
{ leave_button }
|
||||||
<div className="mx_RoomHeader_button">
|
<div className="mx_RoomHeader_button">
|
||||||
<img src="img/search.svg" title="Search" alt="Search" width="21" height="19" onClick={this.props.onSearchClick}/>
|
<img src="img/search.svg" title="Search" alt="Search" width="21" height="19" onClick={this.props.onSearchClick}/>
|
||||||
|
|
|
@ -39,6 +39,7 @@ module.exports = React.createClass({
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {
|
return {
|
||||||
activityMap: null,
|
activityMap: null,
|
||||||
|
isLoadingLeftRooms: false,
|
||||||
lists: {},
|
lists: {},
|
||||||
incomingCall: null,
|
incomingCall: null,
|
||||||
}
|
}
|
||||||
|
@ -47,6 +48,7 @@ module.exports = React.createClass({
|
||||||
componentWillMount: function() {
|
componentWillMount: function() {
|
||||||
var cli = MatrixClientPeg.get();
|
var cli = MatrixClientPeg.get();
|
||||||
cli.on("Room", this.onRoom);
|
cli.on("Room", this.onRoom);
|
||||||
|
cli.on("deleteRoom", this.onDeleteRoom);
|
||||||
cli.on("Room.timeline", this.onRoomTimeline);
|
cli.on("Room.timeline", this.onRoomTimeline);
|
||||||
cli.on("Room.name", this.onRoomName);
|
cli.on("Room.name", this.onRoomName);
|
||||||
cli.on("Room.tags", this.onRoomTags);
|
cli.on("Room.tags", this.onRoomTags);
|
||||||
|
@ -104,7 +106,26 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
onRoom: function(room) {
|
onRoom: function(room) {
|
||||||
this.refreshRoomList();
|
this._delayedRefreshRoomList();
|
||||||
|
},
|
||||||
|
|
||||||
|
onDeleteRoom: function(roomId) {
|
||||||
|
this._delayedRefreshRoomList();
|
||||||
|
},
|
||||||
|
|
||||||
|
onArchivedHeaderClick: function(isHidden) {
|
||||||
|
if (!isHidden) {
|
||||||
|
var self = this;
|
||||||
|
this.setState({ isLoadingLeftRooms: true });
|
||||||
|
// we don't care about the response since it comes down via "Room"
|
||||||
|
// events.
|
||||||
|
MatrixClientPeg.get().syncLeftRooms().catch(function(err) {
|
||||||
|
console.error("Failed to sync left rooms: %s", err);
|
||||||
|
console.error(err);
|
||||||
|
}).finally(function() {
|
||||||
|
self.setState({ isLoadingLeftRooms: false });
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onRoomTimeline: function(ev, room, toStartOfTimeline) {
|
onRoomTimeline: function(ev, room, toStartOfTimeline) {
|
||||||
|
@ -143,22 +164,57 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
onRoomName: function(room) {
|
onRoomName: function(room) {
|
||||||
this.refreshRoomList();
|
this._delayedRefreshRoomList();
|
||||||
},
|
},
|
||||||
|
|
||||||
onRoomTags: function(event, room) {
|
onRoomTags: function(event, room) {
|
||||||
this.refreshRoomList();
|
this._delayedRefreshRoomList();
|
||||||
},
|
},
|
||||||
|
|
||||||
onRoomStateEvents: function(ev, state) {
|
onRoomStateEvents: function(ev, state) {
|
||||||
setTimeout(this.refreshRoomList, 0);
|
this._delayedRefreshRoomList();
|
||||||
},
|
},
|
||||||
|
|
||||||
onRoomMemberName: function(ev, member) {
|
onRoomMemberName: function(ev, member) {
|
||||||
setTimeout(this.refreshRoomList, 0);
|
this._delayedRefreshRoomList();
|
||||||
|
},
|
||||||
|
|
||||||
|
_delayedRefreshRoomList: function() {
|
||||||
|
// There can be 1000s of JS SDK events when rooms are initially synced;
|
||||||
|
// we don't want to do lots of work rendering until things have settled.
|
||||||
|
// Therefore, keep a 1s refresh buffer which will refresh the room list
|
||||||
|
// at MOST once every 1s to prevent thrashing.
|
||||||
|
var MAX_REFRESH_INTERVAL_MS = 1000;
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if (!self._lastRefreshRoomListTs) {
|
||||||
|
self.refreshRoomList(); // first refresh evar
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var timeWaitedMs = Date.now() - self._lastRefreshRoomListTs;
|
||||||
|
if (timeWaitedMs > MAX_REFRESH_INTERVAL_MS) {
|
||||||
|
clearTimeout(self._refreshRoomListTimerId);
|
||||||
|
self._refreshRoomListTimerId = null;
|
||||||
|
self.refreshRoomList(); // refreshed more than MAX_REFRESH_INTERVAL_MS ago
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// refreshed less than MAX_REFRESH_INTERVAL_MS ago, wait the difference
|
||||||
|
// if we aren't already waiting. If we are waiting then NOP, it will
|
||||||
|
// fire soon, promise!
|
||||||
|
if (!self._refreshRoomListTimerId) {
|
||||||
|
self._refreshRoomListTimerId = setTimeout(function() {
|
||||||
|
self.refreshRoomList();
|
||||||
|
}, 10 + MAX_REFRESH_INTERVAL_MS - timeWaitedMs); // 10 is a buffer amount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
refreshRoomList: function() {
|
refreshRoomList: function() {
|
||||||
|
// console.log("DEBUG: Refresh room list delta=%s ms",
|
||||||
|
// (!this._lastRefreshRoomListTs ? "-" : (Date.now() - this._lastRefreshRoomListTs))
|
||||||
|
// );
|
||||||
|
|
||||||
// TODO: rather than bluntly regenerating and re-sorting everything
|
// TODO: rather than bluntly regenerating and re-sorting everything
|
||||||
// every time we see any kind of room change from the JS SDK
|
// every time we see any kind of room change from the JS SDK
|
||||||
// we could do incremental updates on our copy of the state
|
// we could do incremental updates on our copy of the state
|
||||||
|
@ -166,6 +222,7 @@ module.exports = React.createClass({
|
||||||
// us re-rendering all the sublists every time anything changes anywhere
|
// us re-rendering all the sublists every time anything changes anywhere
|
||||||
// in the state of the client.
|
// in the state of the client.
|
||||||
this.setState(this.getRoomLists());
|
this.setState(this.getRoomLists());
|
||||||
|
this._lastRefreshRoomListTs = Date.now();
|
||||||
},
|
},
|
||||||
|
|
||||||
getRoomLists: function() {
|
getRoomLists: function() {
|
||||||
|
@ -184,9 +241,12 @@ module.exports = React.createClass({
|
||||||
if (me && me.membership == "invite") {
|
if (me && me.membership == "invite") {
|
||||||
s.lists["im.vector.fake.invite"].push(room);
|
s.lists["im.vector.fake.invite"].push(room);
|
||||||
}
|
}
|
||||||
|
else if (me && me.membership === "leave") {
|
||||||
|
s.lists["im.vector.fake.archived"].push(room);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
var shouldShowRoom = (
|
var shouldShowRoom = (
|
||||||
me && (me.membership == "join")
|
me && (me.membership == "join" || me.membership === "ban")
|
||||||
);
|
);
|
||||||
|
|
||||||
// hiding conf rooms only ever toggles shouldShowRoom to false
|
// hiding conf rooms only ever toggles shouldShowRoom to false
|
||||||
|
@ -355,7 +415,6 @@ module.exports = React.createClass({
|
||||||
verb="demote"
|
verb="demote"
|
||||||
editable={ true }
|
editable={ true }
|
||||||
order="recent"
|
order="recent"
|
||||||
bottommost={ self.state.lists['im.vector.fake.archived'].length === 0 }
|
|
||||||
activityMap={ self.state.activityMap }
|
activityMap={ self.state.activityMap }
|
||||||
selectedRoom={ self.props.selectedRoom }
|
selectedRoom={ self.props.selectedRoom }
|
||||||
incomingCall={ self.state.incomingCall }
|
incomingCall={ self.state.incomingCall }
|
||||||
|
@ -365,11 +424,14 @@ module.exports = React.createClass({
|
||||||
label="Historical"
|
label="Historical"
|
||||||
editable={ false }
|
editable={ false }
|
||||||
order="recent"
|
order="recent"
|
||||||
bottommost={ true }
|
|
||||||
activityMap={ self.state.activityMap }
|
activityMap={ self.state.activityMap }
|
||||||
selectedRoom={ self.props.selectedRoom }
|
selectedRoom={ self.props.selectedRoom }
|
||||||
incomingCall={ self.state.incomingCall }
|
collapsed={ self.props.collapsed }
|
||||||
collapsed={ self.props.collapsed } />
|
alwaysShowHeader={ true }
|
||||||
|
startAsHidden={ true }
|
||||||
|
showSpinner={ self.state.isLoadingLeftRooms }
|
||||||
|
onHeaderClick= { self.onArchivedHeaderClick }
|
||||||
|
incomingCall={ self.state.incomingCall } />
|
||||||
</div>
|
</div>
|
||||||
</GeminiScrollbar>
|
</GeminiScrollbar>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue