diff --git a/package.json b/package.json index 88c55bcd586..5c11197eac4 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "dependencies": { "babel-polyfill": "^6.5.0", "babel-runtime": "^6.11.6", + "bluebird": "^3.5.0", "browser-request": "^0.3.3", "classnames": "^2.1.2", "draft-js": "^0.8.1", @@ -69,7 +70,6 @@ "matrix-react-sdk": "0.9.7", "modernizr": "^3.1.0", "pako": "^1.0.5", - "q": "^1.4.1", "react": "^15.4.0", "react-dnd": "^2.1.4", "react-dnd-html5-backend": "^2.1.2", diff --git a/src/VectorConferenceHandler.js b/src/VectorConferenceHandler.js index f34a7b732bb..933f59937e2 100644 --- a/src/VectorConferenceHandler.js +++ b/src/VectorConferenceHandler.js @@ -16,7 +16,7 @@ limitations under the License. "use strict"; -var q = require("q"); +import Promise from 'bluebird'; var Matrix = require("matrix-js-sdk"); var Room = Matrix.Room; var CallHandler = require('matrix-react-sdk/lib/CallHandler'); @@ -53,11 +53,11 @@ ConferenceCall.prototype._joinConferenceUser = function() { // Make sure the conference user is in the group chat room var groupRoom = this.client.getRoom(this.groupRoomId); if (!groupRoom) { - return q.reject("Bad group room ID"); + return Promise.reject("Bad group room ID"); } var member = groupRoom.getMember(this.confUserId); if (member && member.membership === "join") { - return q(); + return Promise.resolve(); } return this.client.invite(this.groupRoomId, this.confUserId); }; @@ -75,7 +75,7 @@ ConferenceCall.prototype._getConferenceUserRoom = function() { } } if (confRoom) { - return q(confRoom); + return Promise.resolve(confRoom); } return this.client.createRoom({ preset: "private_chat", diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js index e7d68c39f6a..ea3aa5a29c2 100644 --- a/src/components/structures/RoomDirectory.js +++ b/src/components/structures/RoomDirectory.js @@ -28,7 +28,7 @@ var linkify = require('linkifyjs'); var linkifyString = require('linkifyjs/string'); var linkifyMatrix = require('matrix-react-sdk/lib/linkify-matrix'); var sanitizeHtml = require('sanitize-html'); -var q = require('q'); +import Promise from 'bluebird'; import { _t } from 'matrix-react-sdk/lib/languageHandler'; @@ -117,7 +117,7 @@ module.exports = React.createClass({ }, getMoreRooms: function() { - if (!MatrixClientPeg.get()) return q(); + if (!MatrixClientPeg.get()) return Promise.resolve(); const my_filter_string = this.state.filterString; const my_server = this.state.roomServer; @@ -266,7 +266,7 @@ module.exports = React.createClass({ }, onFillRequest: function(backwards) { - if (backwards || !this.nextBatch) return q(false); + if (backwards || !this.nextBatch) return Promise.resolve(false); return this.getMoreRooms(); }, diff --git a/src/components/views/context_menus/RoomTileContextMenu.js b/src/components/views/context_menus/RoomTileContextMenu.js index a7b19689fec..4d08e8332e4 100644 --- a/src/components/views/context_menus/RoomTileContextMenu.js +++ b/src/components/views/context_menus/RoomTileContextMenu.js @@ -17,7 +17,7 @@ limitations under the License. 'use strict'; -import q from 'q'; +import Promise from 'bluebird'; import React from 'react'; import classNames from 'classnames'; import sdk from 'matrix-react-sdk'; @@ -61,7 +61,7 @@ module.exports = React.createClass({ const roomId = this.props.room.roomId; var cli = MatrixClientPeg.get(); if (!cli.isGuest()) { - q.delay(500).then(function() { + Promise.delay(500).then(function() { if (tagNameOff !== null && tagNameOff !== undefined) { cli.deleteRoomTag(roomId, tagNameOff).finally(function() { // Close the context menu @@ -212,7 +212,7 @@ module.exports = React.createClass({ RoomNotifs.setRoomNotifsState(this.props.room.roomId, newState).done(() => { // delay slightly so that the user can see their state change // before closing the menu - return q.delay(500).then(() => { + return Promise.delay(500).then(() => { if (this._unmounted) return; // Close the context menu if (this.props.onFinished) { diff --git a/src/components/views/settings/Notifications.js b/src/components/views/settings/Notifications.js index 1b8de52d9d5..451a28b8eeb 100644 --- a/src/components/views/settings/Notifications.js +++ b/src/components/views/settings/Notifications.js @@ -17,7 +17,7 @@ limitations under the License. 'use strict'; var React = require('react'); import { _t, _tJsx } from 'matrix-react-sdk/lib/languageHandler'; -var q = require("q"); +import Promise from 'bluebird'; var sdk = require('matrix-react-sdk'); var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); var UserSettingsStore = require('matrix-react-sdk/lib/UserSettingsStore'); @@ -236,7 +236,7 @@ module.exports = React.createClass({ } } - q.all(deferreds).done(function() { + Promise.all(deferreds).done(function() { self._refreshFromServer(); }, function(error) { var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); @@ -306,7 +306,7 @@ module.exports = React.createClass({ } } - q.all(deferreds).done(function(resps) { + Promise.all(deferreds).done(function(resps) { self._refreshFromServer(); }, function(error) { var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); @@ -361,7 +361,7 @@ module.exports = React.createClass({ } // Then, add the new ones - q.all(removeDeferreds).done(function(resps) { + Promise.all(removeDeferreds).done(function(resps) { var deferreds = []; var pushRuleVectorStateKind = self.state.vectorContentRules.vectorState; @@ -399,7 +399,7 @@ module.exports = React.createClass({ } } - q.all(deferreds).done(function(resps) { + Promise.all(deferreds).done(function(resps) { self._refreshFromServer(); }, onError); }, onError); @@ -431,7 +431,9 @@ module.exports = React.createClass({ 'global', kind, LEGACY_RULES[rule.rule_id], portLegacyActions(rule.actions) ).then( function() { return cli.deletePushRule('global', kind, rule.rule_id); - }) + }).catch( (e) => { + console.warn(`Error when porting legacy rule: ${e}`); + }); }(kind, rule)); } } @@ -440,7 +442,7 @@ module.exports = React.createClass({ if (needsUpdate.length > 0) { // If some of the rules need to be ported then wait for the porting // to happen and then fetch the rules again. - return q.allSettled(needsUpdate).then( function() { + return Promise.all(needsUpdate).then( function() { return cli.getPushRules(); }); } else { @@ -594,7 +596,7 @@ module.exports = React.createClass({ self.setState({pushers: resp.pushers}); }); - q.all([pushRulesPromise, pushersPromise]).then(function() { + Promise.all([pushRulesPromise, pushersPromise]).then(function() { self.setState({ phase: self.phases.DISPLAY }); diff --git a/src/vector/index.js b/src/vector/index.js index 81d329c0049..0cf8563f16a 100644 --- a/src/vector/index.js +++ b/src/vector/index.js @@ -65,7 +65,7 @@ var sdk = require("matrix-react-sdk"); const PlatformPeg = require("matrix-react-sdk/lib/PlatformPeg"); sdk.loadSkin(require('../component-index')); var VectorConferenceHandler = require('../VectorConferenceHandler'); -var q = require('q'); +import Promise from 'bluebird'; var request = require('browser-request'); import * as UserSettingsStore from 'matrix-react-sdk/lib/UserSettingsStore'; import * as languageHandler from 'matrix-react-sdk/lib/languageHandler'; @@ -188,7 +188,7 @@ var makeRegistrationUrl = function(params) { window.addEventListener('hashchange', onHashChange); function getConfig() { - let deferred = q.defer(); + let deferred = Promise.defer(); request( { method: "GET", url: "config.json" }, diff --git a/src/vector/platform/ElectronPlatform.js b/src/vector/platform/ElectronPlatform.js index 4f0ffae7337..8e97f23862c 100644 --- a/src/vector/platform/ElectronPlatform.js +++ b/src/vector/platform/ElectronPlatform.js @@ -20,7 +20,7 @@ limitations under the License. import VectorBasePlatform, {updateCheckStatusEnum} from './VectorBasePlatform'; import dis from 'matrix-react-sdk/lib/dispatcher'; import { _t } from 'matrix-react-sdk/lib/languageHandler'; -import q from 'q'; +import Promise from 'bluebird'; import {remote, ipcRenderer} from 'electron'; import rageshake from '../rageshake'; @@ -173,7 +173,7 @@ export default class ElectronPlatform extends VectorBasePlatform { } getAppVersion(): Promise { - return q(remote.app.getVersion()); + return Promise.resolve(remote.app.getVersion()); } startUpdateCheck() { @@ -201,7 +201,7 @@ export default class ElectronPlatform extends VectorBasePlatform { isElectron(): boolean { return true; } requestNotificationPermission(): Promise { - return q('granted'); + return Promise.resolve('granted'); } reload() { diff --git a/src/vector/platform/WebPlatform.js b/src/vector/platform/WebPlatform.js index ae1e54b3078..b88ee93f1d6 100644 --- a/src/vector/platform/WebPlatform.js +++ b/src/vector/platform/WebPlatform.js @@ -21,7 +21,7 @@ import VectorBasePlatform, {updateCheckStatusEnum} from './VectorBasePlatform'; import request from 'browser-request'; import dis from 'matrix-react-sdk/lib/dispatcher.js'; import { _t } from 'matrix-react-sdk/lib/languageHandler'; -import q from 'q'; +import Promise from 'bluebird'; import url from 'url'; import UAParser from 'ua-parser-js'; @@ -68,7 +68,7 @@ export default class WebPlatform extends VectorBasePlatform { // annoyingly, the latest spec says this returns a // promise, but this is only supported in Chrome 46 // and Firefox 47, so adapt the callback API. - const defer = q.defer(); + const defer = Promise.defer(); global.Notification.requestPermission((result) => { defer.resolve(result); }); @@ -103,7 +103,7 @@ export default class WebPlatform extends VectorBasePlatform { } _getVersion(): Promise { - const deferred = q.defer(); + const deferred = Promise.defer(); // We add a cachebuster to the request to make sure that we know about // the most recent version on the origin server. That might not @@ -132,7 +132,7 @@ export default class WebPlatform extends VectorBasePlatform { getAppVersion(): Promise { if (this.runningVersion !== null) { - return q(this.runningVersion); + return Promise.resolve(this.runningVersion); } return this._getVersion(); } diff --git a/src/vector/rageshake.js b/src/vector/rageshake.js index 07726f6834c..d097741471b 100644 --- a/src/vector/rageshake.js +++ b/src/vector/rageshake.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import q from "q"; +import Promise from 'bluebird'; // This module contains all the code needed to log the console, persist it to // disk and submit bug reports. Rationale is as follows: @@ -116,7 +116,7 @@ class IndexedDBLogStore { */ connect() { let req = this.indexedDB.open("logs"); - return q.Promise((resolve, reject) => { + return new Promise((resolve, reject) => { req.onsuccess = (event) => { this.db = event.target.result; // Periodically flush logs to local storage / indexeddb @@ -193,7 +193,7 @@ class IndexedDBLogStore { } // there is no flush promise or there was but it has finished, so do // a brand new one, destroying the chain which may have been built up. - this.flushPromise = q.Promise((resolve, reject) => { + this.flushPromise = new Promise((resolve, reject) => { if (!this.db) { // not connected yet or user rejected access for us to r/w to // the db. @@ -277,7 +277,7 @@ class IndexedDBLogStore { } function deleteLogs(id) { - return q.Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const txn = db.transaction( ["logs", "logslastmod"], "readwrite" ); @@ -375,7 +375,7 @@ class IndexedDBLogStore { */ function selectQuery(store, keyRange, resultMapper) { const query = store.openCursor(keyRange); - return q.Promise((resolve, reject) => { + return new Promise((resolve, reject) => { let results = []; query.onerror = (event) => { reject(new Error("Query failed: " + event.target.errorCode)); diff --git a/src/vector/submit-rageshake.js b/src/vector/submit-rageshake.js index c6c551c61fa..b66ec9abe67 100644 --- a/src/vector/submit-rageshake.js +++ b/src/vector/submit-rageshake.js @@ -15,7 +15,7 @@ limitations under the License. */ import pako from 'pako'; -import q from "q"; +import Promise from 'bluebird'; import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg'; import PlatformPeg from 'matrix-react-sdk/lib/PlatformPeg'; @@ -100,7 +100,7 @@ export default async function sendBugReport(bugReportEndpoint, opts) { } function _submitReport(endpoint, body, progressCallback) { - const deferred = q.defer(); + const deferred = Promise.defer(); const req = new XMLHttpRequest(); req.open("POST", endpoint); diff --git a/test/app-tests/joining.js b/test/app-tests/joining.js index 11fd3d48104..34acd26aeb3 100644 --- a/test/app-tests/joining.js +++ b/test/app-tests/joining.js @@ -33,7 +33,7 @@ var React = require('react'); var ReactDOM = require('react-dom'); var ReactTestUtils = require('react-addons-test-utils'); var expect = require('expect'); -var q = require('q'); +import Promise from 'bluebird'; var test_utils = require('../test-utils'); var MockHttpBackend = require('matrix-mock-request'); @@ -106,7 +106,7 @@ describe('joining a room', function () { .respond(200, {}); function awaitSync(attempts) { if (syncDone) { - return q(); + return Promise.resolve(); } if (!attempts) { throw new Error("Gave up waiting for /sync") @@ -118,7 +118,7 @@ describe('joining a room', function () { // wait for the directory requests httpBackend.when('POST', '/publicRooms').respond(200, {chunk: []}); httpBackend.when('GET', '/thirdparty/protocols').respond(200, {}); - return q.all([ + return Promise.all([ httpBackend.flush('/thirdparty/protocols'), httpBackend.flush('/publicRooms'), ]); @@ -139,14 +139,14 @@ describe('joining a room', function () { httpBackend.when('GET', '/rooms/'+encodeURIComponent(ROOM_ID)+"/initialSync") .respond(401, {errcode: 'M_GUEST_ACCESS_FORBIDDEN'}); - return q.all([ + return Promise.all([ httpBackend.flush('/directory/room/'+encodeURIComponent(ROOM_ALIAS), 1, 200), httpBackend.flush('/rooms/'+encodeURIComponent(ROOM_ID)+"/initialSync", 1, 200), ]); }).then(() => { httpBackend.verifyNoOutstandingExpectation(); - return q.delay(1); + return Promise.delay(1); }).then(() => { // we should now have a roomview, with a preview bar roomView = ReactTestUtils.findRenderedComponentWithType( @@ -164,14 +164,14 @@ describe('joining a room', function () { .respond(200, {room_id: ROOM_ID}); }).then(() => { // wait for the join request to be made - return q.delay(1); + return Promise.delay(1); }).then(() => { // and again, because the state update has to go to the store and // then one dispatch within the store, then to the view // XXX: This is *super flaky*: a better way would be to declare // that we expect a certain state transition to happen, then wait // for that transition to occur. - return q.delay(1); + return Promise.delay(1); }).then(() => { // the roomview should now be loading expect(roomView.state.room).toBe(null); @@ -186,7 +186,7 @@ describe('joining a room', function () { }).then(() => { httpBackend.verifyNoOutstandingExpectation(); - return q.delay(1); + return Promise.delay(1); }).then(() => { // We've joined, expect this to false expect(roomView.state.joining).toBe(false); diff --git a/test/app-tests/loading.js b/test/app-tests/loading.js index 445105ddf4f..c7151aca215 100644 --- a/test/app-tests/loading.js +++ b/test/app-tests/loading.js @@ -22,7 +22,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import ReactTestUtils from 'react-addons-test-utils'; import expect from 'expect'; -import q from 'q'; +import Promise from 'bluebird'; import MatrixReactTestUtils from 'matrix-react-test-utils'; import jssdk from 'matrix-js-sdk'; @@ -104,7 +104,7 @@ describe('loading:', function () { toString: function() { return this.search + this.hash; }, }; - let tokenLoginCompleteDefer = q.defer(); + let tokenLoginCompleteDefer = Promise.defer(); tokenLoginCompletePromise = tokenLoginCompleteDefer.promise; function onNewScreen(screen) { @@ -140,7 +140,7 @@ describe('loading:', function () { realQueryParams={params} startingFragmentQueryParams={fragParts.params} enableGuest={true} - onTokenLoginCompleted={tokenLoginCompleteDefer.resolve} + onTokenLoginCompleted={() => tokenLoginCompleteDefer.resolve()} initialScreenAfterLogin={getScreenFromLocation(windowLocation)} makeRegistrationUrl={() => {throw new Error('Not implemented');}} />, parentDiv @@ -172,7 +172,7 @@ describe('loading:', function () { it('gives a login panel by default', function (done) { loadApp(); - q.delay(1).then(() => { + Promise.delay(1).then(() => { // at this point, we're trying to do a guest registration; // we expect a spinner assertAtLoadingSpinner(matrixChat); @@ -195,7 +195,7 @@ describe('loading:', function () { uriFragment: "#/room/!room:id", }); - q.delay(1).then(() => { + Promise.delay(1).then(() => { // at this point, we're trying to do a guest registration; // we expect a spinner assertAtLoadingSpinner(matrixChat); @@ -207,7 +207,7 @@ describe('loading:', function () { return httpBackend.flush(); }).then(() => { // Wait for another trip around the event loop for the UI to update - return q.delay(10); + return Promise.delay(10); }).then(() => { return completeLogin(matrixChat); }).then(() => { @@ -337,7 +337,7 @@ describe('loading:', function () { }, }); - return q.delay(1).then(() => { + return Promise.delay(1).then(() => { // we expect a loading spinner while we log into the RTS assertAtLoadingSpinner(matrixChat); @@ -401,7 +401,7 @@ describe('loading:', function () { it('shows a home page by default', function (done) { loadApp(); - q.delay(1).then(() => { + Promise.delay(1).then(() => { // at this point, we're trying to do a guest registration; // we expect a spinner assertAtLoadingSpinner(matrixChat); @@ -434,7 +434,7 @@ describe('loading:', function () { loadApp(); - q.delay(1).then(() => { + Promise.delay(1).then(() => { // at this point, we're trying to do a guest registration; // we expect a spinner assertAtLoadingSpinner(matrixChat); @@ -469,7 +469,7 @@ describe('loading:', function () { loadApp({ uriFragment: "#/room/!room:id" }); - q.delay(1).then(() => { + Promise.delay(1).then(() => { // at this point, we're trying to do a guest registration; // we expect a spinner assertAtLoadingSpinner(matrixChat); @@ -557,7 +557,7 @@ describe('loading:', function () { ReactTestUtils.Simulate.click(returnToApp); - return q.delay(1).then(() => { + return Promise.delay(1).then(() => { // we should be straight back into the home page ReactTestUtils.findRenderedComponentWithType( matrixChat, sdk.getComponent('structures.HomePage')); @@ -572,7 +572,7 @@ describe('loading:', function () { queryString: "?loginToken=secretToken&homeserver=https%3A%2F%2Fhomeserver&identityServer=https%3A%2F%2Fidserver", }); - q.delay(1).then(() => { + Promise.delay(1).then(() => { // we expect a spinner while we're logging in assertAtLoadingSpinner(matrixChat); @@ -626,7 +626,7 @@ describe('loading:', function () { return httpBackend.flush().then(() => { // Wait for another trip around the event loop for the UI to update - return q.delay(1); + return Promise.delay(1); }).then(() => { // we expect a spinner ReactTestUtils.findRenderedComponentWithType( @@ -671,7 +671,7 @@ function awaitSyncingSpinner(matrixChat, retryLimit, retryCount) { } // loading can take quite a long time, because we delete the // indexedDB store. - return q.delay(5).then(() => { + return Promise.delay(5).then(() => { return awaitSyncingSpinner(matrixChat, retryLimit, retryCount + 1); }); } @@ -680,7 +680,7 @@ function awaitSyncingSpinner(matrixChat, retryLimit, retryCount) { // state looks good, check the rendered output assertAtSyncingSpinner(matrixChat); - return q(); + return Promise.resolve(); } function assertAtSyncingSpinner(matrixChat) { @@ -708,7 +708,7 @@ function awaitRoomView(matrixChat, retryLimit, retryCount) { throw new Error("MatrixChat still not ready after " + retryCount + " tries"); } - return q.delay(0).then(() => { + return Promise.delay(0).then(() => { return awaitRoomView(matrixChat, retryLimit, retryCount + 1); }); } @@ -718,7 +718,7 @@ function awaitRoomView(matrixChat, retryLimit, retryCount) { // state looks good, check the rendered output ReactTestUtils.findRenderedComponentWithType( matrixChat, sdk.getComponent('structures.RoomView')); - return q(); + return Promise.resolve(); } function awaitLoginComponent(matrixChat, attempts) { diff --git a/test/test-utils.js b/test/test-utils.js index cda9a017b9a..007883df69d 100644 --- a/test/test-utils.js +++ b/test/test-utils.js @@ -1,6 +1,6 @@ "use strict"; -var q = require('q'); +import Promise from 'bluebird'; /** * Perform common actions before each test case, e.g. printing the test case @@ -28,7 +28,7 @@ export function browserSupportsWebRTC() { } export function deleteIndexedDB(dbName) { - return new q.Promise((resolve, reject) => { + return new Promise((resolve, reject) => { if (!window.indexedDB) { resolve(); return;