diff --git a/src/component-index.js b/src/component-index.js
index b391016fcd682265af53f594571745315767be4b..6514fabf61509525220e7a76eb7827f7b6679154 100644
--- a/src/component-index.js
+++ b/src/component-index.js
@@ -23,15 +23,15 @@ limitations under the License.
 
 module.exports.components = {};
 module.exports.components['structures.CreateRoom'] = require('./components/structures/CreateRoom');
-module.exports.components['structures.login.ForgotPassword'] = require('./components/structures/login/ForgotPassword');
-module.exports.components['structures.login.Login'] = require('./components/structures/login/Login');
-module.exports.components['structures.login.PostRegistration'] = require('./components/structures/login/PostRegistration');
-module.exports.components['structures.login.Registration'] = require('./components/structures/login/Registration');
 module.exports.components['structures.MatrixChat'] = require('./components/structures/MatrixChat');
 module.exports.components['structures.RoomView'] = require('./components/structures/RoomView');
 module.exports.components['structures.ScrollPanel'] = require('./components/structures/ScrollPanel');
 module.exports.components['structures.UploadBar'] = require('./components/structures/UploadBar');
 module.exports.components['structures.UserSettings'] = require('./components/structures/UserSettings');
+module.exports.components['structures.login.ForgotPassword'] = require('./components/structures/login/ForgotPassword');
+module.exports.components['structures.login.Login'] = require('./components/structures/login/Login');
+module.exports.components['structures.login.PostRegistration'] = require('./components/structures/login/PostRegistration');
+module.exports.components['structures.login.Registration'] = require('./components/structures/login/Registration');
 module.exports.components['views.avatars.BaseAvatar'] = require('./components/views/avatars/BaseAvatar');
 module.exports.components['views.avatars.MemberAvatar'] = require('./components/views/avatars/MemberAvatar');
 module.exports.components['views.avatars.RoomAvatar'] = require('./components/views/avatars/RoomAvatar');
@@ -54,10 +54,10 @@ module.exports.components['views.login.LoginHeader'] = require('./components/vie
 module.exports.components['views.login.PasswordLogin'] = require('./components/views/login/PasswordLogin');
 module.exports.components['views.login.RegistrationForm'] = require('./components/views/login/RegistrationForm');
 module.exports.components['views.login.ServerConfig'] = require('./components/views/login/ServerConfig');
-module.exports.components['views.messages.MessageEvent'] = require('./components/views/messages/MessageEvent');
 module.exports.components['views.messages.MFileBody'] = require('./components/views/messages/MFileBody');
 module.exports.components['views.messages.MImageBody'] = require('./components/views/messages/MImageBody');
 module.exports.components['views.messages.MVideoBody'] = require('./components/views/messages/MVideoBody');
+module.exports.components['views.messages.MessageEvent'] = require('./components/views/messages/MessageEvent');
 module.exports.components['views.messages.TextualBody'] = require('./components/views/messages/TextualBody');
 module.exports.components['views.messages.TextualEvent'] = require('./components/views/messages/TextualEvent');
 module.exports.components['views.messages.UnknownBody'] = require('./components/views/messages/UnknownBody');
diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js
index debfca338869103caf807165278cfeadc3e9c887..462933cbc66838680ac0762d75d395bd96b74263 100644
--- a/src/components/structures/MatrixChat.js
+++ b/src/components/structures/MatrixChat.js
@@ -662,6 +662,8 @@ module.exports = React.createClass({
 
     onUserClick: function(event, userId) {
         event.preventDefault();
+
+        /*
         var MemberInfo = sdk.getComponent('rooms.MemberInfo');
         var member = new Matrix.RoomMember(null, userId);
         ContextualMenu.createMenu(MemberInfo, {
@@ -669,6 +671,14 @@ module.exports = React.createClass({
             right: window.innerWidth - event.pageX,
             top: event.pageY
         });
+        */
+
+        var member = new Matrix.RoomMember(null, userId);
+        if (!member) { return; }
+        dis.dispatch({
+            action: 'view_user',
+            member: member,
+        });        
     },
 
     onLogoutClick: function(event) {
diff --git a/src/components/views/elements/PowerSelector.js b/src/components/views/elements/PowerSelector.js
index ad258a75227e5fbc0a65df0ac35639e0cb496127..c47c9f38097bfae082e2f11c6d2c673b298756cb 100644
--- a/src/components/views/elements/PowerSelector.js
+++ b/src/components/views/elements/PowerSelector.js
@@ -49,10 +49,16 @@ module.exports = React.createClass({
         this.props.onChange(this.getValue());
     },
 
-    onCustomChange: function(event) {
+    onCustomBlur: function(event) {
         this.props.onChange(this.getValue());
     },
 
+    onCustomKeyDown: function(event) {
+        if (event.key == "Enter") {
+            this.props.onChange(this.getValue());
+        }
+    },
+
     getValue: function() {
         var value;
         if (this.refs.select) {
@@ -72,7 +78,7 @@ module.exports = React.createClass({
                 input = <span>{ this.props.value }</span>
             }
             else {
-                input = <input ref="custom" type="text" size="3" defaultValue={ this.props.value } onChange={ this.onCustomChange } />
+                input = <input ref="custom" type="text" size="3" defaultValue={ this.props.value } onBlur={ this.onCustomBlur } onKeyDown={ this.onCustomKeyDown }/>
             }
             customPicker = <span> of { input }</span>;
         }
diff --git a/src/components/views/rooms/MemberInfo.js b/src/components/views/rooms/MemberInfo.js
index b5f0b88b40718bb8d2a0b8f58b2617f16e013887..a8a601c2d6ef61a556b2c7fb3e17e8f5929686ab 100644
--- a/src/components/views/rooms/MemberInfo.js
+++ b/src/components/views/rooms/MemberInfo.js
@@ -58,15 +58,16 @@ module.exports = React.createClass({
         var roomId = this.props.member.roomId;
         var target = this.props.member.userId;
         MatrixClientPeg.get().kick(roomId, target).done(function() {
-            // NO-OP; rely on the m.room.member event coming down else we could
-            // get out of sync if we force setState here!
-            console.log("Kick success");
-        }, function(err) {
-            Modal.createDialog(ErrorDialog, {
-                title: "Kick error",
-                description: err.message
-            });
-        });
+                // NO-OP; rely on the m.room.member event coming down else we could
+                // get out of sync if we force setState here!
+                console.log("Kick success");
+            }, function(err) {
+                Modal.createDialog(ErrorDialog, {
+                    title: "Kick error",
+                    description: err.message
+                });
+            }
+        );
         this.props.onFinished();
     },
 
@@ -74,16 +75,18 @@ module.exports = React.createClass({
         var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
         var roomId = this.props.member.roomId;
         var target = this.props.member.userId;
-        MatrixClientPeg.get().ban(roomId, target).done(function() {
-            // NO-OP; rely on the m.room.member event coming down else we could
-            // get out of sync if we force setState here!
-            console.log("Ban success");
-        }, function(err) {
-            Modal.createDialog(ErrorDialog, {
-                title: "Ban error",
-                description: err.message
-            });
-        });
+        MatrixClientPeg.get().ban(roomId, target).done(
+            function() {
+                // NO-OP; rely on the m.room.member event coming down else we could
+                // get out of sync if we force setState here!
+                console.log("Ban success");
+            }, function(err) {
+                Modal.createDialog(ErrorDialog, {
+                    title: "Ban error",
+                    description: err.message
+                });
+            }
+        );
         this.props.onFinished();
     },
 
@@ -118,16 +121,17 @@ module.exports = React.createClass({
         }
 
         MatrixClientPeg.get().setPowerLevel(roomId, target, level, powerLevelEvent).done(
-        function() {
-            // NO-OP; rely on the m.room.member event coming down else we could
-            // get out of sync if we force setState here!
-            console.log("Mute toggle success");
-        }, function(err) {
-            Modal.createDialog(ErrorDialog, {
-                title: "Mute error",
-                description: err.message
-            });
-        });
+            function() {
+                // NO-OP; rely on the m.room.member event coming down else we could
+                // get out of sync if we force setState here!
+                console.log("Mute toggle success");
+            }, function(err) {
+                Modal.createDialog(ErrorDialog, {
+                    title: "Mute error",
+                    description: err.message
+                });
+            }
+        );
         this.props.onFinished();        
     },
 
@@ -154,22 +158,55 @@ module.exports = React.createClass({
         }
         var defaultLevel = powerLevelEvent.getContent().users_default;
         var modLevel = me.powerLevel - 1;
+        if (modLevel > 50 && defaultLevel < 50) modLevel = 50; // try to stick with the vector level defaults
         // toggle the level
         var newLevel = this.state.isTargetMod ? defaultLevel : modLevel;
         MatrixClientPeg.get().setPowerLevel(roomId, target, newLevel, powerLevelEvent).done(
-        function() {
-            // NO-OP; rely on the m.room.member event coming down else we could
-            // get out of sync if we force setState here!
-            console.log("Mod toggle success");
-        }, function(err) {
-            Modal.createDialog(ErrorDialog, {
-                title: "Mod error",
-                description: err.message
-            });
-        });
+            function() {
+                // NO-OP; rely on the m.room.member event coming down else we could
+                // get out of sync if we force setState here!
+                console.log("Mod toggle success");
+            }, function(err) {
+                Modal.createDialog(ErrorDialog, {
+                    title: "Mod error",
+                    description: err.message
+                });
+            }
+        );
         this.props.onFinished();        
     },
 
+    onPowerChange: function(powerLevel) {
+        var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
+        var roomId = this.props.member.roomId;
+        var target = this.props.member.userId;
+        var room = MatrixClientPeg.get().getRoom(roomId);
+        if (!room) {
+            this.props.onFinished();
+            return;
+        }
+        var powerLevelEvent = room.currentState.getStateEvents(
+            "m.room.power_levels", ""
+        );
+        if (!powerLevelEvent) {
+            this.props.onFinished();
+            return;
+        }
+        MatrixClientPeg.get().setPowerLevel(roomId, target, powerLevel, powerLevelEvent).done(
+            function() {
+                // NO-OP; rely on the m.room.member event coming down else we could
+                // get out of sync if we force setState here!
+                console.log("Power change success");
+            }, function(err) {
+                Modal.createDialog(ErrorDialog, {
+                    title: "Failure to change power level",
+                    description: err.message
+                });
+            }
+        );
+        this.props.onFinished();        
+    },    
+
     onChatClick: function() {
         // check if there are any existing rooms with just us and them (1:1)
         // If so, just view that room. If not, create a private room with them.
@@ -209,20 +246,22 @@ module.exports = React.createClass({
             MatrixClientPeg.get().createRoom({
                 invite: [this.props.member.userId],
                 preset: "private_chat"
-            }).done(function(res) {
-                self.setState({ creatingRoom: false });
-                dis.dispatch({
-                    action: 'view_room',
-                    room_id: res.room_id
-                });
-                self.props.onFinished();
-            }, function(err) {
-                self.setState({ creatingRoom: false });
-                console.error(
-                    "Failed to create room: %s", JSON.stringify(err)
-                );
-                self.props.onFinished();
-            });
+            }).done(
+                function(res) {
+                    self.setState({ creatingRoom: false });
+                    dis.dispatch({
+                        action: 'view_room',
+                        room_id: res.room_id
+                    });
+                    self.props.onFinished();
+                }, function(err) {
+                    self.setState({ creatingRoom: false });
+                    console.error(
+                        "Failed to create room: %s", JSON.stringify(err)
+                    );
+                    self.props.onFinished();
+                }
+            );
         }
     },
 
@@ -291,9 +330,15 @@ module.exports = React.createClass({
             (powerLevels.events ? powerLevels.events["m.room.power_levels"] : null) ||
             powerLevels.state_default
         );
+        var levelToSend = (
+            (powerLevels.events ? powerLevels.events["m.room.message"] : null) ||
+            powerLevels.events_default
+        );
+
         can.kick = me.powerLevel >= powerLevels.kick;
         can.ban = me.powerLevel >= powerLevels.ban;
         can.mute = me.powerLevel >= editPowerLevel;
+        can.toggleMod = me.powerLevel > them.powerLevel && them.powerLevel >= levelToSend;
         can.modifyLevel = me.powerLevel > them.powerLevel;
         return can;
     },
@@ -317,12 +362,11 @@ module.exports = React.createClass({
     },
 
     render: function() {
-        var interactButton, kickButton, banButton, muteButton, giveModButton, spinner;
-        if (this.props.member.userId === MatrixClientPeg.get().credentials.userId) {
-            interactButton = <div className="mx_MemberInfo_field" onClick={this.onLeaveClick}>Leave room</div>;
-        }
-        else {
-            interactButton = <div className="mx_MemberInfo_field" onClick={this.onChatClick}>Start chat</div>;
+        var startChat, kickButton, banButton, muteButton, giveModButton, spinner;
+        if (this.props.member.userId !== MatrixClientPeg.get().credentials.userId) {
+            // FIXME: we're referring to a vector component from react-sdk
+            var BottomLeftMenuTile = sdk.getComponent('rooms.BottomLeftMenuTile');
+            startChat = <BottomLeftMenuTile collapsed={ false } img="img/create-big.svg" label="Start chat" onClick={ this.onChatClick }/>
         }
 
         if (this.state.creatingRoom) {
@@ -346,35 +390,56 @@ module.exports = React.createClass({
                 {muteLabel}
             </div>;
         }
-        if (this.state.can.modifyLevel) {
-            var giveOpLabel = this.state.isTargetMod ? "Revoke Mod" : "Make Mod";
+        if (this.state.can.toggleMod) {
+            var giveOpLabel = this.state.isTargetMod ? "Revoke Moderator" : "Make Moderator";
             giveModButton = <div className="mx_MemberInfo_field" onClick={this.onModToggle}>
                 {giveOpLabel}
             </div>
         }
 
+        // TODO: we should have an invite button if this MemberInfo is showing a user who isn't actually in the current room yet
+        // e.g. clicking on a linkified userid in a room
+
+        var adminTools;
+        if (kickButton || banButton || muteButton || giveModButton) {
+            adminTools = 
+                <div>
+                    <h3>Admin tools</h3>
+
+                    <div className="mx_MemberInfo_buttons">
+                        {muteButton}
+                        {kickButton}
+                        {banButton}
+                        {giveModButton}
+                    </div>
+                </div>
+        }
+
         var MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
+        var PowerSelector = sdk.getComponent('elements.PowerSelector');
         return (
             <div className="mx_MemberInfo">
                 <img className="mx_MemberInfo_cancel" src="img/cancel.svg" width="18" height="18" onClick={this.onCancel}/>
                 <div className="mx_MemberInfo_avatar">
                     <MemberAvatar member={this.props.member} width={48} height={48} />
                 </div>
+
                 <h2>{ this.props.member.name }</h2>
-                <div className="mx_MemberInfo_profileField">
-                    { this.props.member.userId }
-                </div>
-                <div className="mx_MemberInfo_profileField">
-                    power: { this.props.member.powerLevelNorm }%
-                </div>
-                <div className="mx_MemberInfo_buttons">
-                    {interactButton}
-                    {muteButton}
-                    {kickButton}
-                    {banButton}
-                    {giveModButton}
-                    {spinner}
+
+                <div className="mx_MemberInfo_profile">
+                    <div className="mx_MemberInfo_profileField">
+                        { this.props.member.userId }
+                    </div>
+                    <div className="mx_MemberInfo_profileField">
+                        Level: <b><PowerSelector value={ parseInt(this.props.member.powerLevel) } disabled={ !this.state.can.modifyLevel } onChange={ this.onPowerChange }/></b>
+                    </div>
                 </div>
+
+                { startChat }
+
+                { adminTools }
+
+                { spinner }
             </div>
         );
     }
diff --git a/src/components/views/rooms/MemberTile.js b/src/components/views/rooms/MemberTile.js
index a5dbea65f633268d210cad45f266316179e27ead..0f40180274d19bd8b97014157fd9ca9e079961f2 100644
--- a/src/components/views/rooms/MemberTile.js
+++ b/src/components/views/rooms/MemberTile.js
@@ -83,10 +83,7 @@ module.exports = React.createClass({
         if (!this.props.member) {
             return this._getDisplayName();
         }
-        var label = this.props.member.userId;
-        if (this.state.isTargetMod) {
-            label += " - Mod (" + this.props.member.powerLevelNorm + "%)";
-        }
+        var label = this.props.member.userId + " (power " + this.props.member.powerLevel + ")";
         return label;
     },
 
@@ -120,8 +117,18 @@ module.exports = React.createClass({
             //     var img = "img/p/p" + Math.floor(20 * this.props.member.powerLevelNorm / 100) + ".png";
             //     power = <img src={ img } className="mx_MemberTile_power" width="44" height="44" alt=""/>;
             // }
-        }
 
+            var power;
+            if (this.props.member) {
+                var powerLevel = this.props.member.powerLevel;
+                if (powerLevel >= 50 && powerLevel < 99) {
+                    power = <img src="img/mod.svg" className="mx_MemberTile_power" width="16" height="17" alt="Mod"/>;
+                }
+                if (powerLevel >= 99) {
+                    power = <img src="img/admin.svg" className="mx_MemberTile_power" width="16" height="17" alt="Admin"/>;
+                }
+            }
+        }
 
         var mainClassName = "mx_MemberTile ";
         mainClassName += presenceClass;
@@ -170,7 +177,8 @@ module.exports = React.createClass({
                     onClick={ this.onClick } onMouseEnter={ this.mouseEnter }
                     onMouseLeave={ this.mouseLeave }>
                 <div className="mx_MemberTile_avatar">
-                    {av}
+                    { av }
+                    { power }
                 </div>
                 { nameEl }
             </div>