summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorAlexandre Kühn <aku@odoo.com>2019-09-17 15:10:01 +0000
committerAlexandre Kühn <aku@odoo.com>2019-09-18 10:07:20 +0000
commit9a66619db33fca5f0cb81d9f6bfeb0fb0290cf68 (patch)
tree7f89fa455784ec93ec9d003f515b0d0ea5834a17 /addons
parent3dd2e7c2ef34d76a953089c5a0939ecf3152498e (diff)
[FIX] mail: no wait init_messaging before loading webclient
Before this commit, discuss widgets had to wait for the route `mail/init_messaging`. This behaviour slowed down the loading of the web client. This commit solves the issue by rendering discuss widgets even when `mail/init_messaging` hasn't been resolved. For instance, the messaging menu displays a spinner until messaging becomes ready. Task-Id 2072835 closes odoo/odoo#37031 Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
Diffstat (limited to 'addons')
-rw-r--r--addons/mail/static/src/js/discuss.js134
-rw-r--r--addons/mail/static/src/js/services/mail_document_thread_manager.js2
-rw-r--r--addons/mail/static/src/js/services/mail_manager.js7
-rw-r--r--addons/mail/static/src/js/systray/systray_activity_menu.js3
-rw-r--r--addons/mail/static/src/js/systray/systray_messaging_menu.js25
-rw-r--r--addons/mail/static/src/js/thread_field.js26
-rw-r--r--addons/mail/static/src/scss/discuss.scss12
-rw-r--r--addons/mail/static/src/xml/discuss.xml9
-rw-r--r--addons/mail/static/src/xml/systray.xml2
-rw-r--r--addons/mail/static/tests/discuss_tests.js50
-rw-r--r--addons/mail/static/tests/systray/systray_messaging_menu_tests.js47
11 files changed, 241 insertions, 76 deletions
diff --git a/addons/mail/static/src/js/discuss.js b/addons/mail/static/src/js/discuss.js
index 0c1a39e7b9f..483a1e99d29 100644
--- a/addons/mail/static/src/js/discuss.js
+++ b/addons/mail/static/src/js/discuss.js
@@ -281,6 +281,8 @@ var Discuss = AbstractAction.extend({
this.options.channelQuickSearchThreshold = 20;
}
+ this._isMessagingReady = this.call('mail_service', 'isReady');
+ this._isStarted = false;
this._threadsScrolltop = {};
this._composerStates = {};
this._defaultThreadID = this.options.active_id ||
@@ -292,68 +294,20 @@ var Discuss = AbstractAction.extend({
this._updateThreads.bind(this), 100, { leading: false });
this.controlPanelParams.modelName = 'mail.message';
- },
- /**
- * @override
- */
- willStart: function () {
- return Promise.all([this._super(), this.call('mail_service', 'isReady')]);
+ this.call('mail_service', 'getMailBus').on('messaging_ready', this, this._onMessagingReady);
},
/**
* @override
*/
start: function () {
var self = this;
-
- this._basicComposer = new BasicComposer(this, {
- mentionPartnersRestricted: true,
- showTyping: true,
- });
- this._extendedComposer = new ExtendedComposer(this, {
- mentionPartnersRestricted: true,
- showTyping: true,
+ this._isStarted = true;
+ return this._super.apply(this, arguments).then(function () {
+ if (!self._isMessagingReady) {
+ return;
+ }
+ return self._initRender();
});
- this._basicComposer
- .on('post_message', this, this._onPostMessage)
- .on('input_focused', this, this._onComposerFocused);
- this._extendedComposer
- .on('post_message', this, this._onPostMessage)
- .on('input_focused', this, this._onComposerFocused);
- this._renderButtons();
-
- var defs = [];
- defs.push(
- this._renderThread()
- );
- defs.push(
- this._basicComposer.appendTo(this.$('.o_mail_discuss_content')));
- defs.push(
- this._extendedComposer.appendTo(this.$('.o_mail_discuss_content')));
- defs.push(this._super.apply(this, arguments));
-
- return Promise.all(defs)
- .then(function () {
- return self._setThread(self._defaultThreadID);
- })
- .then(function () {
- self._initThreads();
- self._startListening();
- self._threadWidget.$el.on('scroll', null, _.debounce(function () {
- if (
- self._threadWidget.getScrolltop() < 20 &&
- !self._threadWidget.$('.o_mail_no_content').length &&
- !self._thread.isAllHistoryLoaded(self.domain)
- ) {
- self._loadMoreMessages();
- }
- if (
- self._threadWidget.isAtBottom() &&
- self._thread.getType() !== 'mailbox'
- ) {
- self._thread.markAsRead();
- }
- }, 100));
- });
},
/**
* @override
@@ -382,8 +336,8 @@ var Discuss = AbstractAction.extend({
this.call('mail_service', 'getMailBus').trigger('discuss_open', true);
if (this._thread) {
this._threadWidget.scrollToPosition(this._threadsScrolltop[this._thread.getID()]);
+ this._loadEnoughMessages();
}
- this._loadEnoughMessages();
},
/**
* @override
@@ -548,6 +502,60 @@ var Discuss = AbstractAction.extend({
}
},
/**
+ * @private
+ */
+ _initRender: function () {
+ var self = this;
+ this._basicComposer = new BasicComposer(this, {
+ mentionPartnersRestricted: true,
+ showTyping: true,
+ });
+ this._extendedComposer = new ExtendedComposer(this, {
+ mentionPartnersRestricted: true,
+ showTyping: true,
+ });
+ this._basicComposer
+ .on('post_message', this, this._onPostMessage)
+ .on('input_focused', this, this._onComposerFocused);
+ this._extendedComposer
+ .on('post_message', this, this._onPostMessage)
+ .on('input_focused', this, this._onComposerFocused);
+ this._renderButtons();
+
+ var defs = [];
+ defs.push(
+ this._renderThread()
+ );
+ defs.push(
+ this._basicComposer.appendTo(this.$('.o_mail_discuss_content')));
+ defs.push(
+ this._extendedComposer.appendTo(this.$('.o_mail_discuss_content')));
+
+ return Promise.all(defs)
+ .then(function () {
+ return self._setThread(self._defaultThreadID);
+ })
+ .then(function () {
+ self._initThreads();
+ self._startListening();
+ self._threadWidget.$el.on('scroll', null, _.debounce(function () {
+ if (
+ self._threadWidget.getScrolltop() < 20 &&
+ !self._threadWidget.$('.o_mail_no_content').length &&
+ !self._thread.isAllHistoryLoaded(self.domain)
+ ) {
+ self._loadMoreMessages();
+ }
+ if (
+ self._threadWidget.isAtBottom() &&
+ self._thread.getType() !== 'mailbox'
+ ) {
+ self._thread.markAsRead();
+ }
+ }, 100));
+ });
+ },
+ /**
* Renders the mainside bar with current threads
*
* @private
@@ -1403,6 +1411,20 @@ var Discuss = AbstractAction.extend({
},
/**
* @private
+ */
+ _onMessagingReady: function () {
+ if (this._isMessagingReady) {
+ return;
+ }
+ this._isMessagingReady = true;
+ if (!this._isStarted) {
+ return;
+ }
+ this.$('.o_mail_discuss_loading').remove();
+ this._initRender();
+ },
+ /**
+ * @private
* @param {MouseEvent} ev
*/
_onModerateAllClicked: function (ev) {
diff --git a/addons/mail/static/src/js/services/mail_document_thread_manager.js b/addons/mail/static/src/js/services/mail_document_thread_manager.js
index 6bb66b1b439..652567baf14 100644
--- a/addons/mail/static/src/js/services/mail_document_thread_manager.js
+++ b/addons/mail/static/src/js/services/mail_document_thread_manager.js
@@ -34,7 +34,7 @@ MailManager.include({
this.call('local_storage', 'getItem', key);
}
}
- this.isReady().then(this._updateDocumentThreadWindows.bind(this, this._documentThreadWindowStates));
+ this._mailBus.on('messaging_ready', this, this._updateDocumentThreadWindows.bind(this, this._documentThreadWindowStates));
// listen to localStorage changes to synchronize DocumentThread's
// windows between tabs
this.call('local_storage', 'onStorage', this, this._onStorage);
diff --git a/addons/mail/static/src/js/services/mail_manager.js b/addons/mail/static/src/js/services/mail_manager.js
index 3ed4031abeb..950ac8c5cd6 100644
--- a/addons/mail/static/src/js/services/mail_manager.js
+++ b/addons/mail/static/src/js/services/mail_manager.js
@@ -46,6 +46,7 @@ var PREVIEW_MSG_MAX_SIZE = 350; // optimal for native english speakers
var MailManager = AbstractService.extend({
dependencies: ['ajax', 'bus_service', 'local_storage'],
+ _isReady: false,
_ODOOBOT_ID: ["ODOOBOT", "ODOOBOT"], // authorID for transient messages
/**
@@ -294,7 +295,7 @@ var MailManager = AbstractService.extend({
* This is the case when it has fetched the initial state from the server,
* by means of the route 'mail/init_messaging'
*
- * @returns {Promise}
+ * @returns {boolean}
*/
isReady: function () {
return this._isReady;
@@ -636,7 +637,7 @@ var MailManager = AbstractService.extend({
*/
_fetchMailStateFromServer: function () {
var self = this;
- this._isReady = session.is_bound.then(function () {
+ session.is_bound.then(function () {
var context = _.extend(
{ isMobile: config.device.isMobile },
session.user_context
@@ -648,6 +649,8 @@ var MailManager = AbstractService.extend({
}).then(function (result) {
self._updateInternalStateFromServer(result);
self.call('bus_service', 'startPolling');
+ self._isReady = true;
+ self._mailBus.trigger('messaging_ready');
});
},
/**
diff --git a/addons/mail/static/src/js/systray/systray_activity_menu.js b/addons/mail/static/src/js/systray/systray_activity_menu.js
index 641ff4be1bc..8afa88d7e20 100644
--- a/addons/mail/static/src/js/systray/systray_activity_menu.js
+++ b/addons/mail/static/src/js/systray/systray_activity_menu.js
@@ -19,9 +19,6 @@ var ActivityMenu = Widget.extend({
'click .o_mail_preview': '_onActivityFilterClick',
'show.bs.dropdown': '_onActivityMenuShow',
},
- willStart: function () {
- return Promise.resolve(this.call('mail_service', 'isReady'));
- },
start: function () {
this._$activitiesPreview = this.$('.o_mail_systray_dropdown_items');
this.call('mail_service', 'getMailBus').on('activity_updated', this, this._updateCounter);
diff --git a/addons/mail/static/src/js/systray/systray_messaging_menu.js b/addons/mail/static/src/js/systray/systray_messaging_menu.js
index 4dacae435d4..93024b3b057 100644
--- a/addons/mail/static/src/js/systray/systray_messaging_menu.js
+++ b/addons/mail/static/src/js/systray/systray_messaging_menu.js
@@ -29,18 +29,14 @@ var MessagingMenu = Widget.extend({
/**
* @override
*/
- willStart: function () {
- return Promise.all([this._super.apply(this, arguments), this.call('mail_service', 'isReady')]);
- },
- /**
- * @override
- */
start: function () {
this._$filterButtons = this.$('.o_filter_button');
this._$previews = this.$('.o_mail_systray_dropdown_items');
this._filter = false;
+ this._isMessagingReady = this.call('mail_service', 'isReady');
this._updateCounter();
var mailBus = this.call('mail_service', 'getMailBus');
+ mailBus.on('messaging_ready', this, this._onMessagingReady);
mailBus.on('update_needaction', this, this._updateCounter);
mailBus.on('new_channel', this, this._updateCounter);
mailBus.on('update_thread_unread_counter', this, this._updateCounter);
@@ -206,6 +202,9 @@ var MessagingMenu = Widget.extend({
_updatePreviews: function () {
// Display spinner while waiting for conversations preview
this._$previews.html(QWeb.render('Spinner'));
+ if (!this._isMessagingReady) {
+ return;
+ }
this._getPreviews()
.then(this._renderPreviews.bind(this));
},
@@ -228,7 +227,11 @@ var MessagingMenu = Widget.extend({
* @private
*/
_updateCounter: function () {
+ if (!this._isMessagingReady) {
+ return;
+ }
var counter = this._computeCounter();
+ this.$('.o_mail_messaging_menu_icon').removeClass('fa-spinner fa-spin');
this.$('.o_notification_counter').text(counter);
this.$el.toggleClass('o_no_notification', !counter);
if (this._isShown()) {
@@ -324,6 +327,16 @@ var MessagingMenu = Widget.extend({
}
}
},
+ /**
+ * @private
+ */
+ _onMessagingReady: function () {
+ if (this._isMessagingReady) {
+ return;
+ }
+ this._isMessagingReady = true;
+ this._updateCounter();
+ },
});
// Systray menu items display order matches order in the list
diff --git a/addons/mail/static/src/js/thread_field.js b/addons/mail/static/src/js/thread_field.js
index ab8023b06ad..c8a59850016 100644
--- a/addons/mail/static/src/js/thread_field.js
+++ b/addons/mail/static/src/js/thread_field.js
@@ -20,6 +20,9 @@ var ThreadField = AbstractField.extend({
*/
init: function () {
this._super.apply(this, arguments);
+ this._isMessagingReady = this.call('mail_service', 'isReady');
+ this._isStarted = false;
+ this.call('mail_service', 'getMailBus').on('messaging_ready', this, this._onMessagingReady);
// Used to automatically mark document thread as read at the moment we
// access the document and render the thread.
this._markAsReadOnNextRender = false;
@@ -28,15 +31,10 @@ var ThreadField = AbstractField.extend({
/**
* @override
*/
- willStart: function () {
- return this.alive(this.call('mail_service', 'isReady'));
- },
- /**
- * @override
- */
start: function () {
var self = this;
+ this._isStarted = true;
this.dp = new concurrency.DropPrevious();
this._threadWidget = new ThreadWidget(this, {
@@ -159,6 +157,9 @@ var ThreadField = AbstractField.extend({
* If it is a new document in create mode, unset the document thread.
*/
_setDocumentThread: function () {
+ if (!this._isMessagingReady) {
+ return;
+ }
var params = {
messageIDs: this.value.res_ids,
name: this.recordData.display_name,
@@ -187,6 +188,19 @@ var ThreadField = AbstractField.extend({
},
/**
* @private
+ */
+ _onMessagingReady: function () {
+ if (this._isMessagingReady) {
+ return;
+ }
+ this._isMessagingReady = true;
+ if (!this._isStarted) {
+ return;
+ }
+ this._setDocumentThread();
+ },
+ /**
+ * @private
* @param {mail.model.Message}
*/
_onNewMessage: function (message) {
diff --git a/addons/mail/static/src/scss/discuss.scss b/addons/mail/static/src/scss/discuss.scss
index 0c76829d732..6096d2003cf 100644
--- a/addons/mail/static/src/scss/discuss.scss
+++ b/addons/mail/static/src/scss/discuss.scss
@@ -7,6 +7,18 @@
height: 100%;
overflow: hidden;
+ .o_mail_discuss_loading {
+ display: flex;
+ flex: 1 1 auto;
+ align-items: center;
+ justify-content: center;
+ min-height: 100%;
+
+ > i {
+ margin-right: 5px;
+ }
+ }
+
.o_mail_discuss_sidebar {
width: $o-mail-chat-sidebar-width;
height: 100%;
diff --git a/addons/mail/static/src/xml/discuss.xml b/addons/mail/static/src/xml/discuss.xml
index a4637ad9e02..87d98bc3c49 100644
--- a/addons/mail/static/src/xml/discuss.xml
+++ b/addons/mail/static/src/xml/discuss.xml
@@ -8,8 +8,15 @@
-->
<t t-name="mail.discuss">
<div class="o_mail_discuss">
- <div class="o_mail_discuss_sidebar"/>
+ <div class="o_mail_discuss_sidebar">
+ <div class="o_mail_discuss_loading">
+ <i class="fa fa-spinner fa-spin"/> Please wait...
+ </div>
+ </div>
<div class="o_mail_discuss_content">
+ <div class="o_mail_discuss_loading">
+ <i class="fa fa-spinner fa-spin"/> Please wait...
+ </div>
</div>
</div>
</t>
diff --git a/addons/mail/static/src/xml/systray.xml b/addons/mail/static/src/xml/systray.xml
index db591b31c59..a5677f9da9f 100644
--- a/addons/mail/static/src/xml/systray.xml
+++ b/addons/mail/static/src/xml/systray.xml
@@ -7,7 +7,7 @@
<t t-name="mail.systray.MessagingMenu">
<li class="o_mail_systray_item">
<a class="dropdown-toggle o-no-caret" data-toggle="dropdown" data-display="static" aria-expanded="false" title="Conversations" href="#" role="button">
- <i class="fa fa-comments" role="img" aria-label="Messages"/> <span class="o_notification_counter badge badge-pill"/>
+ <i class="o_mail_messaging_menu_icon fa fa-comments fa-spinner fa-spin" role="img" aria-label="Messages"/> <span class="o_notification_counter badge badge-pill"/>
</a>
<div class="o_mail_systray_dropdown dropdown-menu dropdown-menu-right" role="menu">
<t t-if="widget.isMobile()">
diff --git a/addons/mail/static/tests/discuss_tests.js b/addons/mail/static/tests/discuss_tests.js
index 5e4e831e460..54477874f44 100644
--- a/addons/mail/static/tests/discuss_tests.js
+++ b/addons/mail/static/tests/discuss_tests.js
@@ -115,6 +115,56 @@ QUnit.test('basic rendering', async function (assert) {
discuss.destroy();
});
+QUnit.test('messaging not ready', async function (assert) {
+ assert.expect(9);
+
+ const messagingReadyProm = testUtils.makeTestPromise();
+ const discuss = await createDiscuss({
+ id: 1,
+ context: {},
+ params: {},
+ data: this.data,
+ services: this.services,
+ async mockRPC(route, args) {
+ if (route === '/mail/init_messaging') {
+ const _super = this._super.bind(this, ...arguments); // limitation of class.js
+ assert.step('/mail/init_messaging:pending');
+ await messagingReadyProm;
+ assert.step('/mail/init_messaging:resolved');
+ return _super();
+ }
+ return this._super(...arguments);
+ },
+ });
+
+ assert.verifySteps(['/mail/init_messaging:pending']);
+ assert.ok(
+ discuss.el,
+ "discuss should be rendered");
+ assert.strictEqual(
+ $('.o_action')[0],
+ discuss.el,
+ "should display discuss even when messaging is not ready");
+ assert.containsOnce(
+ discuss,
+ '.o_mail_discuss_sidebar .o_mail_discuss_loading',
+ "should display sidebar is loading (messaging not yet ready)");
+ assert.containsOnce(
+ discuss,
+ '.o_mail_discuss_content .o_mail_discuss_loading',
+ "should display content is loading (messaging not yet ready)");
+
+ messagingReadyProm.resolve();
+ await testUtils.nextTick();
+ assert.verifySteps(['/mail/init_messaging:resolved']);
+ assert.containsNone(
+ discuss,
+ '.o_mail_discuss_loading',
+ "should no longer display sidebar or content is loading (messaging is ready)");
+
+ discuss.destroy();
+});
+
QUnit.test('searchview options visibility', async function (assert) {
assert.expect(5);
diff --git a/addons/mail/static/tests/systray/systray_messaging_menu_tests.js b/addons/mail/static/tests/systray/systray_messaging_menu_tests.js
index 68c37fad438..dcabdc38af3 100644
--- a/addons/mail/static/tests/systray/systray_messaging_menu_tests.js
+++ b/addons/mail/static/tests/systray/systray_messaging_menu_tests.js
@@ -120,6 +120,53 @@ QUnit.test('messaging menu widget: menu with no records', async function (assert
messagingMenu.destroy();
});
+QUnit.test('messaging menu widget: messaging not ready', async function (assert) {
+ assert.expect(8);
+
+ const messagingReadyProm = testUtils.makeTestPromise();
+
+ const messagingMenu = new MessagingMenu();
+ testUtils.mock.addMockEnvironment(messagingMenu, {
+ services: this.services,
+ async mockRPC(route, args) {
+ if (route === '/mail/init_messaging') {
+ const _super = this._super.bind(this, ...arguments); // limitation of class.js
+ assert.step('/mail/init_messaging:pending');
+ await messagingReadyProm;
+ assert.step('/mail/init_messaging:resolved');
+ return _super();
+ }
+ if (args.method === 'message_fetch') {
+ return [];
+ }
+ return this._super(...arguments);
+ },
+ });
+ await messagingMenu.appendTo($('#qunit-fixture'));
+ assert.verifySteps(['/mail/init_messaging:pending']);
+ assert.ok(
+ messagingMenu.el,
+ "messaging menu should be rendered");
+ assert.strictEqual(
+ document.querySelector('.o_mail_systray_item'),
+ messagingMenu.el,
+ "should display messaging menu even when messaging is not ready");
+ assert.hasClass(
+ messagingMenu.$('.o_mail_messaging_menu_icon'),
+ 'fa-spinner',
+ "Messaging menu icon should be a spinner when messaging menu is not ready");
+
+ messagingReadyProm.resolve();
+ await testUtils.nextTick();
+ assert.verifySteps(['/mail/init_messaging:resolved']);
+ assert.doesNotHaveClass(
+ messagingMenu.$('.o_mail_messaging_menu_icon'),
+ 'fa-spinner',
+ "Messaging menu icon should no longer be a spinner when messaging menu is ready");
+
+ messagingMenu.destroy();
+});
+
QUnit.test('messaging menu widget: messaging menu with 1 record', async function (assert) {
assert.expect(3);
var messagingMenu = new MessagingMenu();