Bug 1175825 - Fix text chat room name display when no room name is available (due to crypto failure) and fix a mozL10n warning on Loop desktop. r=mikedeboer
authorMark Banner <standard8@mozilla.com>
Thu, 18 Jun 2015 14:18:03 +0100
changeset 249536 1eddcba043a009810cb3e087be729c4e3d36ea45
parent 249535 5442bb7741fc445b6c5aa72fb8bed66ace5f37a8
child 249537 311cd751719712c09e564d493adba55d2a06d575
push id28929
push userryanvm@gmail.com
push dateThu, 18 Jun 2015 19:51:41 +0000
treeherdermozilla-central@d56a1257088e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmikedeboer
bugs1175825
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1175825 - Fix text chat room name display when no room name is available (due to crypto failure) and fix a mozL10n warning on Loop desktop. r=mikedeboer
browser/components/loop/content/shared/js/textChatStore.js
browser/components/loop/content/shared/js/textChatView.js
browser/components/loop/content/shared/js/textChatView.jsx
browser/components/loop/standalone/content/js/standaloneRoomViews.js
browser/components/loop/standalone/content/js/standaloneRoomViews.jsx
browser/components/loop/test/shared/textChatStore_test.js
--- a/browser/components/loop/content/shared/js/textChatStore.js
+++ b/browser/components/loop/content/shared/js/textChatStore.js
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 var loop = loop || {};
 loop.store = loop.store || {};
 
-loop.store.TextChatStore = (function(mozL10n) {
+loop.store.TextChatStore = (function() {
   "use strict";
 
   var sharedActions = loop.shared.actions;
 
   var CHAT_MESSAGE_TYPES = loop.store.CHAT_MESSAGE_TYPES = {
     RECEIVED: "recv",
     SENT: "sent",
     SPECIAL: "special"
@@ -132,20 +132,22 @@ loop.store.TextChatStore = (function(moz
      * Handles receiving information about the room - specifically the room name
      * so it can be added to the list.
      *
      * @param  {sharedActions.UpdateRoomInfo} actionData
      */
     updateRoomInfo: function(actionData) {
       // XXX When we add special messages to desktop, we'll need to not post
       // multiple changes of room name, only the first. Bug 1171940 should fix this.
-      this._appendTextChatMessage(CHAT_MESSAGE_TYPES.SPECIAL, {
-        contentType: CHAT_CONTENT_TYPES.ROOM_NAME,
-        message: mozL10n.get("rooms_welcome_title", {conversationName: actionData.roomName})
-      });
+      if (actionData.roomName) {
+        this._appendTextChatMessage(CHAT_MESSAGE_TYPES.SPECIAL, {
+          contentType: CHAT_CONTENT_TYPES.ROOM_NAME,
+          message: actionData.roomName
+        });
+      }
 
       // Append the context if we have any.
       if ("urls" in actionData && actionData.urls.length) {
         // We only support the first url at the moment.
         var urlData = actionData.urls[0];
 
         this._appendTextChatMessage(CHAT_MESSAGE_TYPES.SPECIAL, {
           contentType: CHAT_CONTENT_TYPES.CONTEXT,
@@ -155,9 +157,9 @@ loop.store.TextChatStore = (function(moz
             thumbnail: urlData.thumbnail
           }
         });
       }
     }
   });
 
   return TextChatStore;
-})(navigator.mozL10n || window.mozL10n);
+})();
--- a/browser/components/loop/content/shared/js/textChatView.js
+++ b/browser/components/loop/content/shared/js/textChatView.js
@@ -34,16 +34,32 @@ loop.shared.views.TextChatView = (functi
       return (
         React.createElement("div", {className: classes}, 
           React.createElement("p", null, this.props.message)
         )
       );
     }
   });
 
+  var TextChatRoomName = React.createClass({displayName: "TextChatRoomName",
+    mixins: [React.addons.PureRenderMixin],
+
+    propTypes: {
+      message: React.PropTypes.string.isRequired
+    },
+
+    render: function() {
+      return (
+        React.createElement("div", {className: "text-chat-entry special room-name"}, 
+          React.createElement("p", null, mozL10n.get("rooms_welcome_title", {conversationName: this.props.message}))
+        )
+      );
+    }
+  });
+
   /**
    * Manages the text entries in the chat entries view. This is split out from
    * TextChatView so that scrolling can be managed more efficiently - this
    * component only updates when the message list is changed.
    */
   var TextChatEntriesView = React.createClass({displayName: "TextChatEntriesView",
     mixins: [React.addons.PureRenderMixin],
 
@@ -76,31 +92,38 @@ loop.shared.views.TextChatView = (functi
         return null;
       }
 
       return (
         React.createElement("div", {className: "text-chat-entries"}, 
           React.createElement("div", {className: "text-chat-scroller"}, 
             
               this.props.messageList.map(function(entry, i) {
-                if (entry.type === CHAT_MESSAGE_TYPES.SPECIAL &&
-                    entry.contentType === CHAT_CONTENT_TYPES.CONTEXT) {
-                  return (
-                    React.createElement("div", {className: "context-url-view-wrapper"}, 
-                      React.createElement(sharedViews.ContextUrlView, {
-                        allowClick: true, 
-                        description: entry.message, 
-                        dispatcher: this.props.dispatcher, 
-                        key: i, 
-                        showContextTitle: true, 
-                        thumbnail: entry.extraData.thumbnail, 
-                        url: entry.extraData.location, 
-                        useDesktopPaths: false})
-                    )
-                  );
+                if (entry.type === CHAT_MESSAGE_TYPES.SPECIAL) {
+                  switch (entry.contentType) {
+                    case CHAT_CONTENT_TYPES.ROOM_NAME:
+                      return React.createElement(TextChatRoomName, {message: entry.message});
+                    case CHAT_CONTENT_TYPES.CONTEXT:
+                      return (
+                        React.createElement("div", {className: "context-url-view-wrapper"}, 
+                          React.createElement(sharedViews.ContextUrlView, {
+                            allowClick: true, 
+                            description: entry.message, 
+                            dispatcher: this.props.dispatcher, 
+                            key: i, 
+                            showContextTitle: true, 
+                            thumbnail: entry.extraData.thumbnail, 
+                            url: entry.extraData.location, 
+                            useDesktopPaths: false})
+                        )
+                      );
+                    default:
+                      console.error("Unsupported contentType", entry.contentType);
+                      return null;
+                  }
                 }
 
                 return (
                   React.createElement(TextChatEntry, {key: i, 
                                  contentType: entry.contentType, 
                                  message: entry.message, 
                                  type: entry.type})
                 );
--- a/browser/components/loop/content/shared/js/textChatView.jsx
+++ b/browser/components/loop/content/shared/js/textChatView.jsx
@@ -34,16 +34,32 @@ loop.shared.views.TextChatView = (functi
       return (
         <div className={classes}>
           <p>{this.props.message}</p>
         </div>
       );
     }
   });
 
+  var TextChatRoomName = React.createClass({
+    mixins: [React.addons.PureRenderMixin],
+
+    propTypes: {
+      message: React.PropTypes.string.isRequired
+    },
+
+    render: function() {
+      return (
+        <div className="text-chat-entry special room-name">
+          <p>{mozL10n.get("rooms_welcome_title", {conversationName: this.props.message})}</p>
+        </div>
+      );
+    }
+  });
+
   /**
    * Manages the text entries in the chat entries view. This is split out from
    * TextChatView so that scrolling can be managed more efficiently - this
    * component only updates when the message list is changed.
    */
   var TextChatEntriesView = React.createClass({
     mixins: [React.addons.PureRenderMixin],
 
@@ -76,31 +92,38 @@ loop.shared.views.TextChatView = (functi
         return null;
       }
 
       return (
         <div className="text-chat-entries">
           <div className="text-chat-scroller">
             {
               this.props.messageList.map(function(entry, i) {
-                if (entry.type === CHAT_MESSAGE_TYPES.SPECIAL &&
-                    entry.contentType === CHAT_CONTENT_TYPES.CONTEXT) {
-                  return (
-                    <div className="context-url-view-wrapper">
-                      <sharedViews.ContextUrlView
-                        allowClick={true}
-                        description={entry.message}
-                        dispatcher={this.props.dispatcher}
-                        key={i}
-                        showContextTitle={true}
-                        thumbnail={entry.extraData.thumbnail}
-                        url={entry.extraData.location}
-                        useDesktopPaths={false} />
-                    </div>
-                  );
+                if (entry.type === CHAT_MESSAGE_TYPES.SPECIAL) {
+                  switch (entry.contentType) {
+                    case CHAT_CONTENT_TYPES.ROOM_NAME:
+                      return <TextChatRoomName message={entry.message}/>;
+                    case CHAT_CONTENT_TYPES.CONTEXT:
+                      return (
+                        <div className="context-url-view-wrapper">
+                          <sharedViews.ContextUrlView
+                            allowClick={true}
+                            description={entry.message}
+                            dispatcher={this.props.dispatcher}
+                            key={i}
+                            showContextTitle={true}
+                            thumbnail={entry.extraData.thumbnail}
+                            url={entry.extraData.location}
+                            useDesktopPaths={false} />
+                        </div>
+                      );
+                    default:
+                      console.error("Unsupported contentType", entry.contentType);
+                      return null;
+                  }
                 }
 
                 return (
                   <TextChatEntry key={i}
                                  contentType={entry.contentType}
                                  message={entry.message}
                                  type={entry.type} />
                 );
--- a/browser/components/loop/standalone/content/js/standaloneRoomViews.js
+++ b/browser/components/loop/standalone/content/js/standaloneRoomViews.js
@@ -272,16 +272,28 @@ loop.standaloneRoomViews = (function(moz
      */
     componentWillUpdate: function(nextProps, nextState) {
       if (this.state.roomState !== ROOM_STATES.MEDIA_WAIT &&
           nextState.roomState === ROOM_STATES.MEDIA_WAIT) {
         this.props.dispatcher.dispatch(new sharedActions.SetupStreamElements({
           publisherConfig: this.getDefaultPublisherConfig({publishVideo: true})
         }));
       }
+
+      // UX don't want to surface these errors (as they would imply the user
+      // needs to do something to fix them, when if they're having a conversation
+      // they just need to connect). However, we do want there to be somewhere to
+      // find reasonably easily, in case there's issues raised.
+      if (!this.state.roomInfoFailure && nextState.roomInfoFailure) {
+        if (nextState.roomInfoFailure === ROOM_INFO_FAILURES.WEB_CRYPTO_UNSUPPORTED) {
+          console.error(mozL10n.get("room_information_failure_unsupported_browser"));
+        } else {
+          console.error(mozL10n.get("room_information_failure_not_available"));
+        }
+      }
     },
 
     joinRoom: function() {
       this.props.dispatcher.dispatch(new sharedActions.JoinRoom());
     },
 
     leaveRoom: function() {
       this.props.dispatcher.dispatch(new sharedActions.LeaveRoom());
--- a/browser/components/loop/standalone/content/js/standaloneRoomViews.jsx
+++ b/browser/components/loop/standalone/content/js/standaloneRoomViews.jsx
@@ -272,16 +272,28 @@ loop.standaloneRoomViews = (function(moz
      */
     componentWillUpdate: function(nextProps, nextState) {
       if (this.state.roomState !== ROOM_STATES.MEDIA_WAIT &&
           nextState.roomState === ROOM_STATES.MEDIA_WAIT) {
         this.props.dispatcher.dispatch(new sharedActions.SetupStreamElements({
           publisherConfig: this.getDefaultPublisherConfig({publishVideo: true})
         }));
       }
+
+      // UX don't want to surface these errors (as they would imply the user
+      // needs to do something to fix them, when if they're having a conversation
+      // they just need to connect). However, we do want there to be somewhere to
+      // find reasonably easily, in case there's issues raised.
+      if (!this.state.roomInfoFailure && nextState.roomInfoFailure) {
+        if (nextState.roomInfoFailure === ROOM_INFO_FAILURES.WEB_CRYPTO_UNSUPPORTED) {
+          console.error(mozL10n.get("room_information_failure_unsupported_browser"));
+        } else {
+          console.error(mozL10n.get("room_information_failure_not_available"));
+        }
+      }
     },
 
     joinRoom: function() {
       this.props.dispatcher.dispatch(new sharedActions.JoinRoom());
     },
 
     leaveRoom: function() {
       this.props.dispatcher.dispatch(new sharedActions.LeaveRoom());
--- a/browser/components/loop/test/shared/textChatStore_test.js
+++ b/browser/components/loop/test/shared/textChatStore_test.js
@@ -128,67 +128,61 @@ describe("loop.store.TextChatStore", fun
       sinon.assert.calledOnce(window.dispatchEvent);
       sinon.assert.calledWithExactly(window.dispatchEvent,
         new CustomEvent("LoopChatMessageAppended"));
     });
   });
 
   describe("#updateRoomInfo", function() {
     it("should add the room name to the list", function() {
-      sandbox.stub(navigator.mozL10n, "get").returns("Let's really share!");
-
       store.updateRoomInfo(new sharedActions.UpdateRoomInfo({
         roomName: "Let's share!",
         roomOwner: "Mark",
         roomUrl: "fake"
       }));
 
       expect(store.getStoreState("messageList")).eql([{
         type: CHAT_MESSAGE_TYPES.SPECIAL,
         contentType: CHAT_CONTENT_TYPES.ROOM_NAME,
-        message: "Let's really share!",
+        message: "Let's share!",
         extraData: undefined
       }]);
     });
 
     it("should add the context to the list", function() {
-      sandbox.stub(navigator.mozL10n, "get").returns("Let's really share!");
-
       store.updateRoomInfo(new sharedActions.UpdateRoomInfo({
         roomName: "Let's share!",
         roomOwner: "Mark",
         roomUrl: "fake",
         urls: [{
           description: "A wonderful event",
           location: "http://wonderful.invalid",
           thumbnail: "fake"
         }]
       }));
 
       expect(store.getStoreState("messageList")).eql([
         {
           type: CHAT_MESSAGE_TYPES.SPECIAL,
           contentType: CHAT_CONTENT_TYPES.ROOM_NAME,
-          message: "Let's really share!",
+          message: "Let's share!",
           extraData: undefined
         }, {
           type: CHAT_MESSAGE_TYPES.SPECIAL,
           contentType: CHAT_CONTENT_TYPES.CONTEXT,
           message: "A wonderful event",
           extraData: {
             location: "http://wonderful.invalid",
             thumbnail: "fake"
           }
         }
       ]);
     });
 
     it("should not dispatch a LoopChatMessageAppended event", function() {
-      sandbox.stub(navigator.mozL10n, "get").returns("Let's really share!");
-
       store.updateRoomInfo(new sharedActions.UpdateRoomInfo({
         roomName: "Let's share!",
         roomOwner: "Mark",
         roomUrl: "fake"
       }));
 
       sinon.assert.notCalled(window.dispatchEvent);
     });