Bug 1074672 Part 3 - Update the Loop room list to use the new mozLoop.rooms API. r=Standard8 a=loop-only
authorNicolas Perriault <nperriault@gmail.com>
Mon, 27 Oct 2014 20:29:24 +0000
changeset 233776 c7faac3296861bde968f97d8454da062005da98e
parent 233775 5548849a18780656464299cf8c1b11f33fdd180a
child 233777 41e3d6cbff2bf47442efa99a3ba37e482297958b
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersStandard8, loop-only
bugs1074672
milestone35.0a2
Bug 1074672 Part 3 - Update the Loop room list to use the new mozLoop.rooms API. r=Standard8 a=loop-only
browser/components/loop/content/js/panel.js
browser/components/loop/content/js/panel.jsx
browser/components/loop/content/shared/js/actions.js
browser/components/loop/content/shared/js/roomListStore.js
browser/components/loop/test/desktop-local/panel_test.js
browser/components/loop/test/shared/roomListStore_test.js
browser/components/loop/ui/fake-mozLoop.js
browser/components/loop/ui/ui-showcase.js
browser/components/loop/ui/ui-showcase.jsx
--- a/browser/components/loop/content/js/panel.js
+++ b/browser/components/loop/content/js/panel.js
@@ -534,21 +534,17 @@ loop.panel = (function(_, mozL10n) {
       this.props.dispatcher.dispatch(new sharedActions.GetAllRooms());
     },
 
     componentWillUnmount: function() {
       this.stopListening(this.props.store);
     },
 
     _onRoomListChanged: function() {
-      var storeState = this.props.store.getStoreState();
-      this.setState({
-        error: storeState.error,
-        rooms: storeState.rooms
-      });
+      this.setState(this.props.store.getStoreState());
     },
 
     _getListHeading: function() {
       var numRooms = this.state.rooms.length;
       if (numRooms === 0) {
         return mozL10n.get("rooms_list_no_current_conversations");
       }
       return mozL10n.get("rooms_list_current_conversations", {num: numRooms});
--- a/browser/components/loop/content/js/panel.jsx
+++ b/browser/components/loop/content/js/panel.jsx
@@ -534,21 +534,17 @@ loop.panel = (function(_, mozL10n) {
       this.props.dispatcher.dispatch(new sharedActions.GetAllRooms());
     },
 
     componentWillUnmount: function() {
       this.stopListening(this.props.store);
     },
 
     _onRoomListChanged: function() {
-      var storeState = this.props.store.getStoreState();
-      this.setState({
-        error: storeState.error,
-        rooms: storeState.rooms
-      });
+      this.setState(this.props.store.getStoreState());
     },
 
     _getListHeading: function() {
       var numRooms = this.state.rooms.length;
       if (numRooms === 0) {
         return mozL10n.get("rooms_list_no_current_conversations");
       }
       return mozL10n.get("rooms_list_current_conversations", {num: numRooms});
--- a/browser/components/loop/content/shared/js/actions.js
+++ b/browser/components/loop/content/shared/js/actions.js
@@ -130,16 +130,32 @@ loop.shared.actions = (function() {
     /**
      * Retrieves room list.
      * XXX: should move to some roomActions module - refs bug 1079284
      */
     GetAllRooms: Action.define("getAllRooms", {
     }),
 
     /**
+     * An error occured while trying to fetch the room list.
+     * XXX: should move to some roomActions module - refs bug 1079284
+     */
+    GetAllRoomsError: Action.define("getAllRoomsError", {
+      error: String
+    }),
+
+    /**
+     * Updates room list.
+     * XXX: should move to some roomActions module - refs bug 1079284
+     */
+    UpdateRoomList: Action.define("updateRoomList", {
+      roomList: Array
+    }),
+
+    /**
      * Primes localRoomStore with roomLocalId, which triggers the EmptyRoomView
      * to do any necessary setup.
      *
      * XXX should move to localRoomActions module
      */
     SetupEmptyRoom: Action.define("setupEmptyRoom", {
       localRoomId: String
     }),
--- a/browser/components/loop/content/shared/js/roomListStore.js
+++ b/browser/components/loop/content/shared/js/roomListStore.js
@@ -6,59 +6,35 @@
 
 var loop = loop || {};
 loop.store = loop.store || {};
 
 (function() {
   "use strict";
 
   /**
+   * Shared actions.
+   * @type {Object}
+   */
+  var sharedActions = loop.shared.actions;
+
+  /**
    * Room validation schema. See validate.js.
    * @type {Object}
    */
   var roomSchema = {
-    roomToken: String,
-    roomUrl:   String,
-    roomName:  String,
-    maxSize:   Number,
-    currSize:  Number,
-    ctime:     Number
+    roomToken:    String,
+    roomUrl:      String,
+    roomName:     String,
+    maxSize:      Number,
+    participants: Array,
+    ctime:        Number
   };
 
   /**
-   * Temporary sample raw room list data.
-   * XXX Should be removed when we plug the real mozLoop API for rooms.
-   *     See bug 1074664.
-   * @type {Array}
-   */
-  var temporaryRawRoomList = [{
-    roomToken: "_nxD4V4FflQ",
-    roomUrl: "http://sample/_nxD4V4FflQ",
-    roomName: "First Room Name",
-    maxSize: 2,
-    currSize: 0,
-    ctime: 1405517546
-  }, {
-    roomToken: "QzBbvGmIZWU",
-    roomUrl: "http://sample/QzBbvGmIZWU",
-    roomName: "Second Room Name",
-    maxSize: 2,
-    currSize: 0,
-    ctime: 1405517418
-  }, {
-    roomToken: "3jKS_Els9IU",
-    roomUrl: "http://sample/3jKS_Els9IU",
-    roomName: "Third Room Name",
-    maxSize: 3,
-    clientMaxSize: 2,
-    currSize: 1,
-    ctime: 1405518241
-  }];
-
-  /**
    * Room type. Basically acts as a typed object constructor.
    *
    * @param {Object} values Room property values.
    */
   function Room(values) {
     var validatedData = new loop.validate.Validator(roomSchema || {})
                                          .validate(values || {});
     for (var prop in validatedData) {
@@ -90,17 +66,19 @@ loop.store = loop.store || {};
 
     if (!options.mozLoop) {
       throw new Error("Missing option mozLoop");
     }
     this.mozLoop = options.mozLoop;
 
     this.dispatcher.register(this, [
       "getAllRooms",
-      "openRoom"
+      "getAllRoomsError",
+      "openRoom",
+      "updateRoomList"
     ]);
   }
 
   RoomListStore.prototype = _.extend({
     /**
      * Retrieves current store state.
      *
      * @return {Object}
@@ -115,31 +93,16 @@ loop.store = loop.store || {};
      * @param {Object} state The new store state.
      */
     setStoreState: function(state) {
       this.storeState = state;
       this.trigger("change");
     },
 
     /**
-     * Proxy to navigator.mozLoop.rooms.getAll.
-     * XXX Could probably be removed when bug 1074664 lands.
-     *
-     * @param  {Function} cb Callback(error, roomList)
-     */
-    _fetchRoomList: function(cb) {
-      // Faking this.mozLoop.rooms until it's available; bug 1074664.
-      if (!this.mozLoop.hasOwnProperty("rooms")) {
-        cb(null, temporaryRawRoomList);
-        return;
-      }
-      this.mozLoop.rooms.getAll(cb);
-    },
-
-    /**
      * Maps and sorts the raw room list received from the mozLoop API.
      *
      * @param  {Array} rawRoomList Raw room list.
      * @return {Array}
      */
     _processRawRoomList: function(rawRoomList) {
       if (!rawRoomList) {
         return [];
@@ -153,19 +116,43 @@ loop.store = loop.store || {};
           return b.ctime - a.ctime;
         });
     },
 
     /**
      * Gather the list of all available rooms from the MozLoop API.
      */
     getAllRooms: function() {
-      this._fetchRoomList(function(err, rawRoomList) {
-        this.setStoreState({
-          error: err,
-          rooms: this._processRawRoomList(rawRoomList)
-        });
+      this.mozLoop.rooms.getAll(function(err, rawRoomList) {
+        var action;
+        if (err) {
+          action = new sharedActions.GetAllRoomsError({error: err});
+        } else {
+          action = new sharedActions.UpdateRoomList({roomList: rawRoomList});
+        }
+        this.dispatcher.dispatch(action);
       }.bind(this));
-    }
+    },
+
+    /**
+     * Updates current error state in case getAllRooms failed.
+     *
+     * @param {sharedActions.UpdateRoomListError} actionData The action data.
+     */
+    getAllRoomsError: function(actionData) {
+      this.setStoreState({error: actionData.error});
+    },
+
+    /**
+     * Updates current room list.
+     *
+     * @param {sharedActions.UpdateRoomList} actionData The action data.
+     */
+    updateRoomList: function(actionData) {
+      this.setStoreState({
+        error: undefined,
+        rooms: this._processRawRoomList(actionData.roomList)
+      });
+    },
   }, Backbone.Events);
 
   loop.store.RoomListStore = RoomListStore;
 })();
--- a/browser/components/loop/test/desktop-local/panel_test.js
+++ b/browser/components/loop/test/desktop-local/panel_test.js
@@ -44,16 +44,21 @@ describe("loop.panel", function() {
       noteCallUrlExpiry: sinon.spy(),
       composeEmail: sinon.spy(),
       telemetryAdd: sinon.spy(),
       contacts: {
         getAll: function(callback) {
           callback(null, []);
         },
         on: sandbox.stub()
+      },
+      rooms: {
+        getAll: function(callback) {
+          callback(null, []);
+        }
       }
     };
 
     document.mozL10n.initialize(navigator.mozLoop);
     // XXX prevent a race whenever mozL10n hasn't been initialized yet
     setTimeout(done, 0);
   });
 
--- a/browser/components/loop/test/shared/roomListStore_test.js
+++ b/browser/components/loop/test/shared/roomListStore_test.js
@@ -45,32 +45,32 @@ describe("loop.store.RoomListStore", fun
 
   describe("#getAllRooms", function() {
     var store, fakeMozLoop;
     var fakeRoomList = [{
       roomToken: "_nxD4V4FflQ",
       roomUrl: "http://sample/_nxD4V4FflQ",
       roomName: "First Room Name",
       maxSize: 2,
-      currSize: 0,
+      participants: [],
       ctime: 1405517546
     }, {
       roomToken: "QzBbvGmIZWU",
       roomUrl: "http://sample/QzBbvGmIZWU",
       roomName: "Second Room Name",
       maxSize: 2,
-      currSize: 0,
+      participants: [],
       ctime: 1405517418
     }, {
       roomToken: "3jKS_Els9IU",
       roomUrl: "http://sample/3jKS_Els9IU",
       roomName: "Third Room Name",
       maxSize: 3,
       clientMaxSize: 2,
-      currSize: 1,
+      participants: [],
       ctime: 1405518241
     }];
 
     beforeEach(function() {
       fakeMozLoop = {
         rooms: {
           getAll: function(cb) {
             cb(null, fakeRoomList);
@@ -88,28 +88,28 @@ describe("loop.store.RoomListStore", fun
         done();
       });
 
       dispatcher.dispatch(new sharedActions.GetAllRooms());
     });
 
     it("should fetch the room list from the mozLoop API", function(done) {
       store.once("change", function() {
-        expect(store.getStoreState().error).to.be.a.null;
+        expect(store.getStoreState().error).to.be.a.undefined;
         expect(store.getStoreState().rooms).to.have.length.of(3);
         done();
       });
 
       dispatcher.dispatch(new sharedActions.GetAllRooms());
     });
 
     it("should order the room list using ctime desc", function(done) {
       store.once("change", function() {
         var storeState = store.getStoreState();
-        expect(storeState.error).to.be.a.null;
+        expect(storeState.error).to.be.a.undefined;
         expect(storeState.rooms[0].ctime).eql(1405518241);
         expect(storeState.rooms[1].ctime).eql(1405517546);
         expect(storeState.rooms[2].ctime).eql(1405517418);
         done();
       });
 
       dispatcher.dispatch(new sharedActions.GetAllRooms());
     });
--- a/browser/components/loop/ui/fake-mozLoop.js
+++ b/browser/components/loop/ui/fake-mozLoop.js
@@ -1,12 +1,53 @@
 /* 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/. */
 
+// Sample from https://wiki.mozilla.org/Loop/Architecture/Rooms#GET_.2Frooms
+var fakeRooms = [
+  {
+    "roomToken": "_nxD4V4FflQ",
+    "roomName": "First Room Name",
+    "roomUrl": "http://localhost:3000/rooms/_nxD4V4FflQ",
+    "roomOwner": "Alexis",
+    "maxSize": 2,
+    "creationTime": 1405517546,
+    "ctime": 1405517546,
+    "expiresAt": 1405534180,
+    "participants": []
+  },
+  {
+    "roomToken": "QzBbvGmIZWU",
+    "roomName": "Second Room Name",
+    "roomUrl": "http://localhost:3000/rooms/QzBbvGmIZWU",
+    "roomOwner": "Alexis",
+    "maxSize": 2,
+    "creationTime": 1405517546,
+    "ctime": 1405517546,
+    "expiresAt": 1405534180,
+    "participants": []
+  },
+  {
+    "roomToken": "3jKS_Els9IU",
+    "roomName": "UX Discussion",
+    "roomUrl": "http://localhost:3000/rooms/3jKS_Els9IU",
+    "roomOwner": "Alexis",
+    "maxSize": 2,
+    "clientMaxSize": 2,
+    "creationTime": 1405517546,
+    "ctime": 1405517818,
+    "expiresAt": 1405534180,
+    "participants": [
+       { "displayName": "Alexis", "account": "alexis@example.com", "roomConnectionId": "2a1787a6-4a73-43b5-ae3e-906ec1e763cb" },
+       { "displayName": "Adam", "roomConnectionId": "781f012b-f1ea-4ce1-9105-7cfc36fb4ec7" }
+     ]
+  }
+];
+
 /**
  * Faking the mozLoop object which doesn't exist in regular web pages.
  * @type {Object}
  */
 navigator.mozLoop = {
   ensureRegistered: function() {},
   getLoopCharPref: function() {},
   getLoopBoolPref: function(pref) {
@@ -17,10 +58,15 @@ navigator.mozLoop = {
   },
   releaseCallData: function() {},
   contacts: {
     getAll: function(callback) {
       callback(null, []);
     },
     on: function() {}
   },
+  rooms: {
+    getAll: function(callback) {
+      callback(null, fakeRooms);
+    }
+  },
   fxAEnabled: true
 };
--- a/browser/components/loop/ui/ui-showcase.js
+++ b/browser/components/loop/ui/ui-showcase.js
@@ -54,17 +54,17 @@
     "https://input.allizom.org/api/v1/feedback", {
       product: "Loop"
     }
   );
 
   var dispatcher = new loop.Dispatcher();
   var roomListStore = new loop.store.RoomListStore({
     dispatcher: dispatcher,
-    mozLoop: {}
+    mozLoop: navigator.mozLoop
   });
 
   // Local mocks
 
   var mockContact = {
     name: ["Mr Smith"],
     email: [{
       value: "smith@invalid.com"
--- a/browser/components/loop/ui/ui-showcase.jsx
+++ b/browser/components/loop/ui/ui-showcase.jsx
@@ -54,17 +54,17 @@
     "https://input.allizom.org/api/v1/feedback", {
       product: "Loop"
     }
   );
 
   var dispatcher = new loop.Dispatcher();
   var roomListStore = new loop.store.RoomListStore({
     dispatcher: dispatcher,
-    mozLoop: {}
+    mozLoop: navigator.mozLoop
   });
 
   // Local mocks
 
   var mockContact = {
     name: ["Mr Smith"],
     email: [{
       value: "smith@invalid.com"