From 4013dae7702400f0cf2dedf20471e9fc8307719b Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 4 Feb 2016 15:26:12 +0000 Subject: [PATCH 1/6] Start refactoring RoomSettings - Don't manipulate settings in RoomView. Make it RoomSettings' job. - Return Promise[] from AliasSettings.save() rather than an allSettled promise so callers can have more granularity over what to do with it (.all vs .allSettled) - General refactoring of RoomSettings. Most things are broken now and are not submitted. Add util methods to grab values out of events. --- src/components/structures/RoomView.js | 235 +++--------------- .../views/room_settings/AliasSettings.js | 2 +- src/components/views/rooms/RoomSettings.js | 147 +++++++++-- 3 files changed, 153 insertions(+), 231 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 9b772b8e42..febafacc22 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1038,195 +1038,6 @@ module.exports = React.createClass({ return ret; }, - uploadNewState: function(newVals) { - var old_name = this.state.room.name; - - var old_topic = this.state.room.currentState.getStateEvents('m.room.topic', ''); - if (old_topic) { - old_topic = old_topic.getContent().topic; - } else { - old_topic = ""; - } - - var old_join_rule = this.state.room.currentState.getStateEvents('m.room.join_rules', ''); - if (old_join_rule) { - old_join_rule = old_join_rule.getContent().join_rule; - } else { - old_join_rule = "invite"; - } - - var old_history_visibility = this.state.room.currentState.getStateEvents('m.room.history_visibility', ''); - if (old_history_visibility) { - old_history_visibility = old_history_visibility.getContent().history_visibility; - } else { - old_history_visibility = "shared"; - } - - var old_guest_read = (old_history_visibility === "world_readable"); - - var old_guest_join = this.state.room.currentState.getStateEvents('m.room.guest_access', ''); - if (old_guest_join) { - old_guest_join = (old_guest_join.getContent().guest_access === "can_join"); - } - else { - old_guest_join = false; - } - - var deferreds = []; - - if (old_name != newVals.name && newVals.name != undefined) { - deferreds.push( - MatrixClientPeg.get().setRoomName(this.state.room.roomId, newVals.name) - ); - } - - if (old_topic != newVals.topic && newVals.topic != undefined) { - deferreds.push( - MatrixClientPeg.get().setRoomTopic(this.state.room.roomId, newVals.topic) - ); - } - - if (old_join_rule != newVals.join_rule && newVals.join_rule != undefined) { - deferreds.push( - MatrixClientPeg.get().sendStateEvent( - this.state.room.roomId, "m.room.join_rules", { - join_rule: newVals.join_rule, - }, "" - ) - ); - } - - // XXX: EVIL HACK: for now, don't let Vector clobber 'joined' visibility to 'invited' - // just because it doesn't know about 'joined' yet. In future we should fix it - // properly - https://github.com/vector-im/vector-web/issues/731 - if (old_history_visibility === "joined") { - old_history_visibility = "invited"; - } - - var visibilityDeferred; - if (old_history_visibility != newVals.history_visibility && - newVals.history_visibility != undefined) { - 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( - "global", this.state.room.roomId, newVals.are_notifications_muted - ) - ); - - if (newVals.power_levels) { - deferreds.push( - MatrixClientPeg.get().sendStateEvent( - this.state.room.roomId, "m.room.power_levels", newVals.power_levels, "" - ) - ); - } - - if (newVals.tag_operations) { - var oplist = []; - for (var i = 0; i < newVals.tag_operations.length; i++) { - var tag_operation = newVals.tag_operations[i]; - switch (tag_operation.type) { - case 'put': - oplist.push( - MatrixClientPeg.get().setRoomTag( - this.props.roomId, tag_operation.tag, {} - ) - ); - break; - case 'delete': - oplist.push( - MatrixClientPeg.get().deleteRoomTag( - this.props.roomId, tag_operation.tag - ) - ); - break; - default: - console.log("Unknown tag operation, ignoring: " + tag_operation.type); - } - } - - if (oplist.length) { - var deferred = oplist[0]; - oplist.splice(1).forEach(function (f) { - deferred = deferred.then(f); - }); - deferreds.push(deferred); - } - } - - if (newVals.color_scheme) { - deferreds.push( - MatrixClientPeg.get().setRoomAccountData( - this.state.room.roomId, "org.matrix.room.color_scheme", newVals.color_scheme - ) - ); - } - - deferreds.push(this.refs.room_settings.saveAliases()); - - if (deferreds.length) { - var self = this; - q.allSettled(deferreds).then( - function(results) { - var fails = results.filter(function(result) { return result.state !== "fulfilled" }); - if (fails.length) { - fails.forEach(function(result) { - console.error(result.reason); - }); - var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - Modal.createDialog(ErrorDialog, { - title: "Failed to set state", - description: fails.map(function(result) { return result.reason }).join("\n"), - }); - self.refs.room_settings.resetState(); - } - else { - self.setState({ - editingRoomSettings: false - }); - } - }).finally(function() { - self.setState({ - uploadingRoomSettings: false, - }); - }); - } else { - this.setState({ - editingRoomSettings: false, - uploadingRoomSettings: false, - }); - } - }, - _collectEventNode: function(eventId, node) { if (this.eventNodes == undefined) this.eventNodes = {}; this.eventNodes[eventId] = node; @@ -1324,22 +1135,38 @@ module.exports = React.createClass({ this.showSettings(true); }, - onSaveClick: function() { + onSettingsSaveClick: function() { this.setState({ uploadingRoomSettings: true, }); - - this.uploadNewState({ - name: this.refs.header.getRoomName(), - topic: this.refs.header.getTopic(), - join_rule: this.refs.room_settings.getJoinRules(), - history_visibility: this.refs.room_settings.getHistoryVisibility(), - are_notifications_muted: this.refs.room_settings.areNotificationsMuted(), - power_levels: this.refs.room_settings.getPowerLevels(), - tag_operations: this.refs.room_settings.getTagOperations(), - guest_join: this.refs.room_settings.canGuestsJoin(), - guest_read: this.refs.room_settings.canGuestsRead(), - color_scheme: this.refs.room_settings.getColorScheme(), + + this.refs.room_settings.setName(this.refs.header.getRoomName()); + this.refs.room_settings.setTopic(this.refs.header.getTopic()); + + this.refs.room_settings.save().then((results) => { + console.log("Settings saved."); + var fails = results.filter(function(result) { return result.state !== "fulfilled" }); + if (fails.length) { + fails.forEach(function(result) { + console.error(result.reason); + }); + var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); + Modal.createDialog(ErrorDialog, { + title: "Failed to set state", + description: fails.map(function(result) { return result.reason }).join("\n"), + }); + // still editing room settings + } + else { + this.setState({ + editingRoomSettings: false + }); + } + }).finally(() => { + this.setState({ + uploadingRoomSettings: false, + editingRoomSettings: false + }); }); }, @@ -1730,7 +1557,7 @@ module.exports = React.createClass({ var aux = null; if (this.state.editingRoomSettings) { - aux = ; + aux = ; } else if (this.state.uploadingRoomSettings) { aux = ; @@ -1899,7 +1726,7 @@ module.exports = React.createClass({ editing={this.state.editingRoomSettings} onSearchClick={this.onSearchClick} onSettingsClick={this.onSettingsClick} - onSaveClick={this.onSaveClick} + onSaveClick={this.onSettingsSaveClick} onCancelClick={this.onCancelClick} onForgetClick={ (myMember && myMember.membership === "leave") ? this.onForgetClick : null diff --git a/src/components/views/room_settings/AliasSettings.js b/src/components/views/room_settings/AliasSettings.js index 0dd00852fa..033fdcd8b5 100644 --- a/src/components/views/room_settings/AliasSettings.js +++ b/src/components/views/room_settings/AliasSettings.js @@ -114,7 +114,7 @@ module.exports = React.createClass({ } } - return q.allSettled(promises); + return promises; }, aliasEventsToDictionary: function(aliasEvents) { // m.room.alias events diff --git a/src/components/views/rooms/RoomSettings.js b/src/components/views/rooms/RoomSettings.js index b716b2e9df..27fc6af961 100644 --- a/src/components/views/rooms/RoomSettings.js +++ b/src/components/views/rooms/RoomSettings.js @@ -21,7 +21,7 @@ var Tinter = require('../../../Tinter'); var sdk = require('../../../index'); var Modal = require('../../../Modal'); -var room_colors = [ +var ROOM_COLORS = [ // magic room default values courtesy of Ribot ["#76cfa6", "#eaf5f0"], ["#81bddb", "#eaf1f4"], @@ -53,8 +53,8 @@ module.exports = React.createClass({ if (color_scheme.primary_color) color_scheme.primary_color = color_scheme.primary_color.toLowerCase(); if (color_scheme.secondary_color) color_scheme.secondary_color = color_scheme.secondary_color.toLowerCase(); // XXX: we should validate these values - for (var i = 0; i < room_colors.length; i++) { - var room_color = room_colors[i]; + for (var i = 0; i < ROOM_COLORS.length; i++) { + var room_color = ROOM_COLORS[i]; if (room_color[0] === color_scheme.primary_color && room_color[1] === color_scheme.secondary_color) { @@ -64,8 +64,8 @@ module.exports = React.createClass({ } if (room_color_index === undefined) { // append the unrecognised colours to our palette - room_color_index = room_colors.length; - room_colors[room_color_index] = [ color_scheme.primary_color, color_scheme.secondary_color ]; + room_color_index = ROOM_COLORS.length; + ROOM_COLORS[room_color_index] = [ color_scheme.primary_color, color_scheme.secondary_color ]; } } else { @@ -77,14 +77,84 @@ module.exports = React.createClass({ tags[tagName] = {}; }); + var are_notifications_muted = false; + var roomPushRule = MatrixClientPeg.get().getRoomPushRule("global", this.props.room.roomId); + if (roomPushRule) { + if (0 <= roomPushRule.actions.indexOf("dont_notify")) { + are_notifications_muted = true; + } + } + + return { + name: this._yankValueFromEvent("m.room.name", "name"), + topic: this._yankValueFromEvent("m.room.topic", "topic"), + join_rule: this._yankValueFromEvent("m.room.join_rules", "join_rule"), + history_visibility: this._yankValueFromEvent("m.room.history_visibility", "history_visibility"), + guest_access: this._yankValueFromEvent("m.room.guest_access", "guest_access"), power_levels_changed: false, color_scheme_changed: false, color_scheme_index: room_color_index, tags_changed: false, tags: tags, + areNotifsMuted: are_notifications_muted }; }, + + setName: function(name) { + this.setState({ + name: name + }); + }, + + setTopic: function(topic) { + this.setState({ + topic: topic + }); + }, + + save: function() { + var stateWasSetDefer = q.defer(); + // the caller may have JUST called setState on stuff, so we need to re-render before saving + // else we won't use the latest values of things. + // We can be a bit cheeky here and set a loading flag, and listen for the callback on that + // to know when things have been set. + this.setState({ _loading: true}, () => { + stateWasSetDefer.resolve(); + this.setState({ _loading: false}); + }); + + return stateWasSetDefer.promise.then(() => { + return this._save(); + }); + }, + + _save: function() { + const roomId = this.props.room.roomId; + var promises = this.saveAliases(); // returns Promise[] + var originalState = this.getInitialState(); + // diff between original state and this.state to work out what has been changed + console.log("Original: %s", JSON.stringify(originalState)); + console.log("New: %s", JSON.stringify(this.state)); + if (this.state.name !== originalState.name) { + promises.push(MatrixClientPeg.get().setRoomName(roomId, this.state.name)); + } + if (this.state.topic !== originalState.topic) { // TODO: 0-length strings? + promises.push(MatrixClientPeg.get().setRoomTopic(roomId, this.state.topic)); + } + // TODO: + // this.state.join_rule + // this.state.history_visibility + // this.state.guest_access + // setRoomMutePushRule + // power levels + // tags + // color scheme + + // submit diffs + + return q.allSettled(promises); + }, saveAliases: function() { if (!this.refs.alias_settings) { return q(); } @@ -116,7 +186,7 @@ module.exports = React.createClass({ }, areNotificationsMuted: function() { - return this.refs.are_notifications_muted.checked; + return this.state.are_notifications_muted; }, getPowerLevels: function() { @@ -178,20 +248,36 @@ module.exports = React.createClass({ if (!this.state.color_scheme_changed) return undefined; return { - primary_color: room_colors[this.state.color_scheme_index][0], - secondary_color: room_colors[this.state.color_scheme_index][1], + primary_color: ROOM_COLORS[this.state.color_scheme_index][0], + secondary_color: ROOM_COLORS[this.state.color_scheme_index][1], }; }, onColorSchemeChanged: function(index) { // preview what the user just changed the scheme to. - Tinter.tint(room_colors[index][0], room_colors[index][1]); + Tinter.tint(ROOM_COLORS[index][0], ROOM_COLORS[index][1]); this.setState({ color_scheme_changed: true, color_scheme_index: index, }); }, + + _yankValueFromEvent: function(stateEventType, keyName, defaultValue) { + // E.g.("m.room.name","name") would yank the "name" content key from "m.room.name" + var event = this.props.room.currentState.getStateEvents(stateEventType, ''); + if (!event) { + return defaultValue; + } + return event.getContent()[keyName] || defaultValue; + }, + + _onToggle: function(keyName, ev) { + console.log("Checkbox toggle: %s %s", keyName, ev.target.checked); + var state = {}; + state[keyName] = ev.target.checked; + this.setState(state); + }, onTagChange: function(tagName, event) { if (event.target.checked) { @@ -223,8 +309,7 @@ module.exports = React.createClass({ var EditableText = sdk.getComponent('elements.EditableText'); var PowerSelector = sdk.getComponent('elements.PowerSelector'); - var join_rule = this.props.room.currentState.getStateEvents('m.room.join_rules', ''); - if (join_rule) join_rule = join_rule.getContent().join_rule; + var history_visibility = this.props.room.currentState.getStateEvents('m.room.history_visibility', ''); if (history_visibility) history_visibility = history_visibility.getContent().history_visibility; @@ -235,14 +320,6 @@ module.exports = React.createClass({ guest_access = guest_access.getContent().guest_access; } - var are_notifications_muted; - var roomPushRule = MatrixClientPeg.get().getRoomPushRule("global", this.props.room.roomId); - if (roomPushRule) { - if (0 <= roomPushRule.actions.indexOf("dont_notify")) { - are_notifications_muted = true; - } - } - var events_levels = (power_levels ? power_levels.events : {}) || {}; var user_id = MatrixClientPeg.get().credentials.userId; @@ -315,7 +392,7 @@ module.exports = React.createClass({

Room Colour

- {room_colors.map(function(room_color, i) { + {ROOM_COLORS.map(function(room_color, i) { var selected; if (i === self.state.color_scheme_index) { selected = @@ -418,12 +495,30 @@ module.exports = React.createClass({ { tags_section }
- - - - - - + + + + + +
From 73df5a2828694485d7839386431327a4a6851af1 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 4 Feb 2016 16:18:59 +0000 Subject: [PATCH 2/6] Modify how checked state is passed around Prefer onChange -> setState to ref grabbing so we can expose public setters and not be tied down to certain element implementations. --- src/components/views/rooms/RoomSettings.js | 34 +++++++--------------- 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/src/components/views/rooms/RoomSettings.js b/src/components/views/rooms/RoomSettings.js index 27fc6af961..78e8e734a0 100644 --- a/src/components/views/rooms/RoomSettings.js +++ b/src/components/views/rooms/RoomSettings.js @@ -165,10 +165,6 @@ module.exports = React.createClass({ this.setState(this.getInitialState()); }, - canGuestsJoin: function() { - return this.refs.guests_join.checked; - }, - canGuestsRead: function() { return this.refs.guests_read.checked; }, @@ -177,10 +173,6 @@ module.exports = React.createClass({ return this.refs.topic ? this.refs.topic.value : ""; }, - getJoinRules: function() { - return this.refs.is_private.checked ? "invite" : "public"; - }, - getHistoryVisibility: function() { return this.refs.share_history.checked ? "shared" : "invited"; }, @@ -272,10 +264,10 @@ module.exports = React.createClass({ return event.getContent()[keyName] || defaultValue; }, - _onToggle: function(keyName, ev) { + _onToggle: function(keyName, checkedValue, uncheckedValue, ev) { console.log("Checkbox toggle: %s %s", keyName, ev.target.checked); var state = {}; - state[keyName] = ev.target.checked; + state[keyName] = ev.target.checked ? checkedValue : uncheckedValue; this.setState(state); }, @@ -309,16 +301,7 @@ module.exports = React.createClass({ var EditableText = sdk.getComponent('elements.EditableText'); var PowerSelector = sdk.getComponent('elements.PowerSelector'); - - - var history_visibility = this.props.room.currentState.getStateEvents('m.room.history_visibility', ''); - if (history_visibility) history_visibility = history_visibility.getContent().history_visibility; - var power_levels = this.props.room.currentState.getStateEvents('m.room.power_levels', ''); - var guest_access = this.props.room.currentState.getStateEvents('m.room.guest_access', ''); - if (guest_access) { - guest_access = guest_access.getContent().guest_access; - } var events_levels = (power_levels ? power_levels.events : {}) || {}; @@ -496,23 +479,26 @@ module.exports = React.createClass({
- { room_colors_section } +
+

Room Colour

+ +
Date: Fri, 5 Feb 2016 11:59:19 +0000 Subject: [PATCH 4/6] Glue more things back together --- src/components/structures/RoomView.js | 2 +- src/components/views/rooms/RoomSettings.js | 99 ++++++++++------------ 2 files changed, 45 insertions(+), 56 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index c73be1ffd0..83dc1c3631 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1245,7 +1245,7 @@ module.exports = React.createClass({ uploadingRoomSettings: false, editingRoomSettings: false }); - }); + }).done(); }, onCancelClick: function() { diff --git a/src/components/views/rooms/RoomSettings.js b/src/components/views/rooms/RoomSettings.js index 24246c393b..6153ccbc2c 100644 --- a/src/components/views/rooms/RoomSettings.js +++ b/src/components/views/rooms/RoomSettings.js @@ -19,6 +19,7 @@ var React = require('react'); var MatrixClientPeg = require('../../../MatrixClientPeg'); var sdk = require('../../../index'); var Modal = require('../../../Modal'); +var ObjectUtils = require("../../../ObjectUtils"); module.exports = React.createClass({ displayName: 'RoomSettings', @@ -88,28 +89,65 @@ module.exports = React.createClass({ const roomId = this.props.room.roomId; var promises = this.saveAliases(); // returns Promise[] var originalState = this.getInitialState(); + // diff between original state and this.state to work out what has been changed console.log("Original: %s", JSON.stringify(originalState)); console.log("New: %s", JSON.stringify(this.state)); + + // name and topic if (this._hasDiff(this.state.name, originalState.name)) { promises.push(MatrixClientPeg.get().setRoomName(roomId, this.state.name)); } if (this._hasDiff(this.state.topic, originalState.topic)) { promises.push(MatrixClientPeg.get().setRoomTopic(roomId, this.state.topic)); } + // TODO: // this.state.join_rule // this.state.history_visibility // this.state.guest_access + // setRoomMutePushRule + if (this.state.areNotifsMuted !== originalState.areNotifsMuted) { + promises.push(MatrixClientPeg.get().setRoomMutePushRule( + "global", roomId, this.state.areNotifsMuted + )); + } + // power levels + var powerLevels = this._getPowerLevels(); + if (powerLevels) { + promises.push(MatrixClientPeg.get().sendStateEvent( + roomId, "m.room.power_levels", powerLevels, "" + )); + } + // tags + if (this.state.tags_changed) { + var tagDiffs = ObjectUtils.getKeyValueArrayDiffs(originalState.tags, this.state.tags); + // [ {place: add, key: "m.favourite", val: "yep"} ] + tagDiffs.forEach(function(diff) { + switch (diff.place) { + case "add": + promises.push( + MatrixClientPeg.get().setRoomTag(roomId, diff.key, {}) + ); + break; + case "del": + promises.push( + MatrixClientPeg.get().deleteRoomTag(roomId, diff.key) + ); + break; + default: + console.error("Unknown tag operation: %s", diff.place); + break; + } + }); + } // color scheme promises.push(this.saveColor()); - // submit diffs - return q.allSettled(promises); }, @@ -131,27 +169,7 @@ module.exports = React.createClass({ return strA !== strB; }, - resetState: function() { - this.setState(this.getInitialState()); - }, - - canGuestsRead: function() { - return this.refs.guests_read.checked; - }, - - getTopic: function() { - return this.refs.topic ? this.refs.topic.value : ""; - }, - - getHistoryVisibility: function() { - return this.refs.share_history.checked ? "shared" : "invited"; - }, - - areNotificationsMuted: function() { - return this.state.are_notifications_muted; - }, - - getPowerLevels: function() { + _getPowerLevels: function() { if (!this.state.power_levels_changed) return undefined; var power_levels = this.props.room.currentState.getStateEvents('m.room.power_levels', ''); @@ -172,34 +190,6 @@ module.exports = React.createClass({ return new_power_levels; }, - getTagOperations: function() { - if (!this.state.tags_changed) return undefined; - - var ops = []; - - var delta = {}; - Object.keys(this.props.room.tags).forEach(function(oldTag) { - delta[oldTag] = delta[oldTag] || 0; - delta[oldTag]--; - }); - Object.keys(this.state.tags).forEach(function(newTag) { - delta[newTag] = delta[newTag] || 0; - delta[newTag]++; - }); - Object.keys(delta).forEach(function(tag) { - if (delta[tag] == 1) { - ops.push({ type: "put", tag: tag }); - } else if (delta[tag] == -1) { - ops.push({ type: "delete", tag: tag }); - } else { - console.error("Calculated tag delta of " + delta[tag] + - " - this should never happen!"); - } - }); - - return ops; - }, - onPowerLevelsChanged: function() { this.setState({ power_levels_changed: true @@ -222,7 +212,7 @@ module.exports = React.createClass({ this.setState(state); }, - onTagChange: function(tagName, event) { + _onTagChange: function(tagName, event) { if (event.target.checked) { if (tagName === 'm.favourite') { delete this.state.tags['m.lowpriority']; @@ -231,13 +221,12 @@ module.exports = React.createClass({ delete this.state.tags['m.favourite']; } - this.state.tags[tagName] = this.state.tags[tagName] || {}; + this.state.tags[tagName] = this.state.tags[tagName] || ["yep"]; } else { delete this.state.tags[tagName]; } - // XXX: hacky say to deep-edit state this.setState({ tags: this.state.tags, tags_changed: true @@ -390,7 +379,7 @@ module.exports = React.createClass({ + onChange={ self._onTagChange.bind(self, tag.name) }/> { tag.label } ); }) : tags.map(function(tag) { return tag.label; }).join(", ") From 03f19eba556ec18ad36d2244ce109b58ac80ff07 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Fri, 5 Feb 2016 14:38:28 +0000 Subject: [PATCH 5/6] Implement radio boxes ( vector-im/vector-web#731 ) for history visibility. Hook up remaining bits. --- src/components/structures/RoomView.js | 4 +- src/components/views/rooms/RoomSettings.js | 76 ++++++++++++++++++---- 2 files changed, 64 insertions(+), 16 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 83dc1c3631..5a3dcbd094 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1222,15 +1222,15 @@ module.exports = React.createClass({ this.refs.room_settings.setTopic(this.refs.header.getTopic()); this.refs.room_settings.save().then((results) => { - console.log("Settings saved."); var fails = results.filter(function(result) { return result.state !== "fulfilled" }); + console.log("Settings saved with %s errors", fails.length); if (fails.length) { fails.forEach(function(result) { console.error(result.reason); }); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { - title: "Failed to set state", + title: "Failed to save settings", description: fails.map(function(result) { return result.reason }).join("\n"), }); // still editing room settings diff --git a/src/components/views/rooms/RoomSettings.js b/src/components/views/rooms/RoomSettings.js index 6153ccbc2c..3642fbca42 100644 --- a/src/components/views/rooms/RoomSettings.js +++ b/src/components/views/rooms/RoomSettings.js @@ -102,12 +102,31 @@ module.exports = React.createClass({ promises.push(MatrixClientPeg.get().setRoomTopic(roomId, this.state.topic)); } - // TODO: - // this.state.join_rule - // this.state.history_visibility - // this.state.guest_access + if (this.state.history_visibility !== originalState.history_visibility) { + promises.push(MatrixClientPeg.get().sendStateEvent( + roomId, "m.room.history_visibility", + { history_visibility: this.state.history_visibility }, + "" + )); + } + + if (this.state.join_rule !== originalState.join_rule) { + promises.push(MatrixClientPeg.get().sendStateEvent( + roomId, "m.room.join_rules", + { join_rule: this.state.join_rule }, + "" + )); + } + + if (this.state.guest_access !== originalState.guest_access) { + promises.push(MatrixClientPeg.get().sendStateEvent( + roomId, "m.room.guest_access", + { guest_access: this.state.guest_access }, + "" + )); + } + - // setRoomMutePushRule if (this.state.areNotifsMuted !== originalState.areNotifsMuted) { promises.push(MatrixClientPeg.get().setRoomMutePushRule( "global", roomId, this.state.areNotifsMuted @@ -144,6 +163,7 @@ module.exports = React.createClass({ } }); } + console.log("Performing %s operations", promises.length); // color scheme promises.push(this.saveColor()); @@ -204,6 +224,12 @@ module.exports = React.createClass({ } return event.getContent()[keyName] || defaultValue; }, + + _onHistoryRadioToggle: function(ev) { + this.setState({ + history_visibility: ev.target.value + }); + }, _onToggle: function(keyName, checkedValue, uncheckedValue, ev) { console.log("Checkbox toggle: %s %s", keyName, ev.target.checked); @@ -386,6 +412,10 @@ module.exports = React.createClass({ }
+ // If there is no history_visibility, it is assumed to be 'shared'. + // http://matrix.org/docs/spec/r0.0.0/client_server.html#id31 + var historyVisibility = this.state.history_visibility || "shared"; + // FIXME: disable guests_read if the user hasn't turned on shared history return (
@@ -402,20 +432,38 @@ module.exports = React.createClass({ defaultChecked={this.state.join_rule !== "public"}/> Make this room private - - +
+

Who can read history?

+ + + + +