[IMP] mail, mail_bot: improved push notifications permission response
This commit makes small improvements on the messaging menu with
the new module `mail_bot`:
[IMP] When OdooBot has a request, it now adds "+1" to the counter of
the messaging menu. The related preview also has a bold title,
and displays "(1)" next to the title.
[REF] Static previews are no longer in mail_service. This was only
used for "OdooBot has a request" preview. This logic has now
been moved to the module `mail_bot` (was previously in `mail`).
[FIX] Title of response of push notifications permission clearly
states whether permission has been granted or denied
(was displaying "[Object object]" before this commit).
Task-ID 1877502
This commit is contained in:
@@ -46,7 +46,6 @@ var PREVIEW_MSG_MAX_SIZE = 350; // optimal for native english speakers
|
||||
var MailManager = AbstractService.extend({
|
||||
dependencies: ['ajax', 'bus_service', 'local_storage'],
|
||||
_ODOOBOT_ID: "ODOOBOT", // default authorID for transient messages
|
||||
IS_STATIC_PREVIEW_ENABLED: true,
|
||||
|
||||
/**
|
||||
* @override
|
||||
@@ -232,17 +231,13 @@ var MailManager = AbstractService.extend({
|
||||
var inboxDef = this._getSystrayInboxPreviews(filter);
|
||||
var failureDef = this._getSystrayMailFailurePreviews(filter);
|
||||
defs = defs.concat([channelDef, inboxDef, failureDef]);
|
||||
if (this.IS_STATIC_PREVIEW_ENABLED) {
|
||||
var staticDef = this._getSystrayStaticPreviews(filter);
|
||||
defs.push(staticDef);
|
||||
}
|
||||
return $.when.apply($, defs)
|
||||
.then(function (previewsChannel, previewsInbox, previewsFailure, previewsStatic) {
|
||||
.then(function (previewsChannel, previewsInbox, previewsFailure) {
|
||||
// order: failures > inbox > channel, each group must be sorted
|
||||
previewsChannel = self._sortPreviews(previewsChannel);
|
||||
previewsInbox = self._sortPreviews(previewsInbox);
|
||||
previewsFailure = self._sortPreviews(previewsFailure);
|
||||
return _.union(previewsStatic, previewsFailure, previewsInbox, previewsChannel);
|
||||
return _.union(previewsFailure, previewsInbox, previewsChannel);
|
||||
});
|
||||
},
|
||||
/**
|
||||
@@ -816,30 +811,6 @@ var MailManager = AbstractService.extend({
|
||||
return $.when([]);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Get the previews of static systray elements, adding notification request
|
||||
*
|
||||
* @private
|
||||
* @param {string|undefined} [filter]
|
||||
* @returns {$.Promise<Object[]>} resolved with list of object that are
|
||||
* compatible with preview template of mail systray menu
|
||||
*/
|
||||
_getSystrayStaticPreviews: function (filter) {
|
||||
var elems = [];
|
||||
if (
|
||||
window.Notification && window.Notification.permission === "default" &&
|
||||
(filter === 'mailbox_inbox' || !filter)
|
||||
) {
|
||||
elems.push({
|
||||
title: _t("OdooBot has a request"),
|
||||
imageSRC: "/mail/static/src/img/odoobot.png",
|
||||
status: 'bot',
|
||||
body: _t("Enable desktop notifications to chat"),
|
||||
id: 'request_notification',
|
||||
});
|
||||
}
|
||||
return $.when(elems);
|
||||
},
|
||||
/**
|
||||
* Initialize the internal state of the mail service. Ensure that all
|
||||
* attributes are set before doing any operation on them.
|
||||
|
||||
@@ -7,8 +7,6 @@ var SystrayMenu = require('web.SystrayMenu');
|
||||
var Widget = require('web.Widget');
|
||||
var QWeb = core.qweb;
|
||||
|
||||
var _t = core._t;
|
||||
|
||||
/**
|
||||
* Menu item appended in the systray part of the navbar
|
||||
*
|
||||
@@ -91,6 +89,35 @@ var MessagingMenu = Widget.extend({
|
||||
});
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Compute the counter next to the systray messaging menu. This counter is
|
||||
* the sum of unread messages in channels, the counter of the mailbox inbox,
|
||||
* and the amount of mail failures.
|
||||
*
|
||||
* @private
|
||||
* @returns {integer}
|
||||
*/
|
||||
_computeCounter: function () {
|
||||
var channels = this.call('mail_service', 'getChannels');
|
||||
var channelUnreadCounters = _.map(channels, function (channel) {
|
||||
return channel.getUnreadCounter();
|
||||
});
|
||||
var unreadChannelCounter = _.reduce(channelUnreadCounters, function (c1, c2) {
|
||||
return c1 + c2;
|
||||
}, 0);
|
||||
var inboxCounter = this.call('mail_service', 'getMailbox', 'inbox').getMailboxCounter();
|
||||
var mailFailureCounter = this.call('mail_service', 'getMailFailures').length;
|
||||
|
||||
return unreadChannelCounter + inboxCounter + mailFailureCounter;
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {$.Promise<Object[]>} resolved with list of previews that are
|
||||
* compatible with the 'mail.Preview' template.
|
||||
*/
|
||||
_getPreviews: function () {
|
||||
return this.call('mail_service', 'getSystrayPreviews', this._filter);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @return {boolean} whether the messaging menu is shown or not.
|
||||
@@ -152,27 +179,6 @@ var MessagingMenu = Widget.extend({
|
||||
previews: previews,
|
||||
}));
|
||||
},
|
||||
/**
|
||||
* Display the browser notification request dialog when the user clicks on systray's corresponding notification
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_requestNotificationPermission: function () {
|
||||
var self = this;
|
||||
var def = window.Notification && window.Notification.requestPermission();
|
||||
if (def) {
|
||||
def.then(function (value) {
|
||||
if (value !== 'granted') {
|
||||
self.call('bus_service', 'sendNotification', self, _t('Permission denied'),
|
||||
_t('Odoo will not have the permission to send native notifications on this device.'));
|
||||
} else {
|
||||
self.call('bus_service', 'sendNotification', self, _t('Permission granted'),
|
||||
_t('Odoo has now the permission to send you native notifications on this device.'));
|
||||
}
|
||||
});
|
||||
}
|
||||
this.$(".o_mail_navbar_request_permission").slideUp();
|
||||
},
|
||||
/**
|
||||
* Get and render list of previews, based on the selected filter
|
||||
*
|
||||
@@ -200,7 +206,7 @@ var MessagingMenu = Widget.extend({
|
||||
_updatePreviews: function () {
|
||||
// Display spinner while waiting for conversations preview
|
||||
this._$previews.html(QWeb.render('Spinner'));
|
||||
this.call('mail_service', 'getSystrayPreviews', this._filter)
|
||||
this._getPreviews()
|
||||
.then(this._renderPreviews.bind(this));
|
||||
},
|
||||
/**
|
||||
@@ -222,19 +228,7 @@ var MessagingMenu = Widget.extend({
|
||||
* @private
|
||||
*/
|
||||
_updateCounter: function () {
|
||||
var counter;
|
||||
|
||||
var channels = this.call('mail_service', 'getChannels');
|
||||
var channelUnreadCounters = _.map(channels, function (channel) {
|
||||
return channel.getUnreadCounter();
|
||||
});
|
||||
var unreadChannelCounter = _.reduce(channelUnreadCounters, function (c1, c2) {
|
||||
return c1 + c2;
|
||||
}, 0);
|
||||
var inboxCounter = this.call('mail_service', 'getMailbox', 'inbox').getMailboxCounter();
|
||||
var mailFailureCounter = this.call('mail_service', 'getMailFailures').length;
|
||||
|
||||
counter = unreadChannelCounter + inboxCounter + mailFailureCounter;
|
||||
var counter = this._computeCounter();
|
||||
this.$('.o_notification_counter').text(counter);
|
||||
this.$el.toggleClass('o_no_notification', !counter);
|
||||
if (this._isShown()) {
|
||||
@@ -289,8 +283,6 @@ var MessagingMenu = Widget.extend({
|
||||
var documentID = $target.data('document-id');
|
||||
var documentModel = $target.data('document-model');
|
||||
this._openDocument(documentModel, documentID);
|
||||
} else if (previewID === 'request_notification') {
|
||||
this._requestNotificationPermission();
|
||||
} else {
|
||||
// preview of thread
|
||||
this.call('mail_service', 'openThread', previewID);
|
||||
@@ -301,7 +293,7 @@ var MessagingMenu = Widget.extend({
|
||||
* as read
|
||||
*
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onClickPreviewMarkAsRead: function (ev) {
|
||||
ev.stopPropagation();
|
||||
|
||||
@@ -84,12 +84,7 @@ QUnit.module('Document Thread', {
|
||||
partner_id: partnerID, // so that needaction messages are treated as needactions
|
||||
};
|
||||
this.services = mailTestUtils.getMailServices();
|
||||
this.MailService = this.services.mail_service;
|
||||
this.MailService.prototype.IS_STATIC_PREVIEW_ENABLED = false;
|
||||
},
|
||||
afterEach: function () {
|
||||
this.MailService.prototype.IS_STATIC_PREVIEW_ENABLED = true;
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test('open a document thread in a thread window', function (assert) {
|
||||
|
||||
@@ -58,11 +58,8 @@ QUnit.module('MessagingMenu (Mail Failures)', {
|
||||
};
|
||||
|
||||
this.services = mailTestUtils.getMailServices();
|
||||
this.MailService = this.services.mail_service;
|
||||
this.MailService.prototype.IS_STATIC_PREVIEW_ENABLED = false;
|
||||
},
|
||||
afterEach: function () {
|
||||
this.MailService.prototype.IS_STATIC_PREVIEW_ENABLED = true;
|
||||
// unpatch _.debounce and _.throttle
|
||||
_.debounce = this.underscoreDebounce;
|
||||
_.throttle = this.underscoreThrottle;
|
||||
|
||||
@@ -93,11 +93,8 @@ QUnit.module('MessagingMenu', {
|
||||
},
|
||||
};
|
||||
this.services = mailTestUtils.getMailServices();
|
||||
this.MailService = this.services.mail_service;
|
||||
this.MailService.prototype.IS_STATIC_PREVIEW_ENABLED = false;
|
||||
},
|
||||
afterEach: function () {
|
||||
this.MailService.prototype.IS_STATIC_PREVIEW_ENABLED = true;
|
||||
// unpatch _.debounce and _.throttle
|
||||
_.debounce = this.underscoreDebounce;
|
||||
_.throttle = this.underscoreThrottle;
|
||||
|
||||
@@ -5,8 +5,9 @@ var AbstractService = require('web.AbstractService');
|
||||
var core = require('web.core');
|
||||
var session = require('web.session');
|
||||
|
||||
var _t = core._t;
|
||||
|
||||
var MailBotService = AbstractService.extend({
|
||||
name: 'mailbot_service',
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
@@ -22,7 +23,40 @@ var MailBotService = AbstractService.extend({
|
||||
}, 2*60*1000);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Get the previews related to the OdooBot (conversation not included).
|
||||
* For instance, when there is no conversation with OdooBot and OdooBot has
|
||||
* a request, it should display a preview in the systray messaging menu.
|
||||
*
|
||||
* @param {string|undefined} [filter]
|
||||
* @returns {Object[]} list of objects that are compatible with the
|
||||
* 'mail.Preview' template.
|
||||
*/
|
||||
getPreviews: function (filter) {
|
||||
var previews = [];
|
||||
if (this.hasRequest() && (filter === 'mailbox_inbox' || !filter)) {
|
||||
previews.push({
|
||||
title: _t("OdooBot has a request"),
|
||||
imageSRC: "/mail/static/src/img/odoobot.png",
|
||||
status: 'bot',
|
||||
body: _t("Enable desktop notifications to chat"),
|
||||
id: 'request_notification',
|
||||
unreadCounter: 1,
|
||||
});
|
||||
}
|
||||
return previews;
|
||||
},
|
||||
/**
|
||||
* Tell whether OdooBot has a request or not.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
hasRequest: function () {
|
||||
return window.Notification && window.Notification.permission === "default";
|
||||
},
|
||||
});
|
||||
|
||||
core.serviceRegistry.add('mailbot_service', MailBotService);
|
||||
return MailBotService;
|
||||
|
||||
});
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
odoo.define('mail_bot.systray.MessagingMenu', function (require) {
|
||||
"use strict";
|
||||
|
||||
var MessagingMenu = require('mail.systray.MessagingMenu');
|
||||
var core = require('web.core');
|
||||
|
||||
var _t = core._t;
|
||||
|
||||
return MessagingMenu.include({
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Override so that 'mailbot has a request' is included in the computation
|
||||
* of of the counter.
|
||||
*
|
||||
* @override
|
||||
* @private
|
||||
* @returns {integer}
|
||||
*/
|
||||
_computeCounter: function () {
|
||||
var counter = this._super.apply(this, arguments);
|
||||
if (this.call('mailbot_service', 'hasRequest')) {
|
||||
counter++;
|
||||
}
|
||||
return counter;
|
||||
},
|
||||
/**
|
||||
* Override so that the mailbot previews are included in the systray
|
||||
* messaging menu (e.g. 'OdooBot has a request')
|
||||
*
|
||||
* @override
|
||||
* @private
|
||||
* @returns {$.Promise<Object[]>} resolved with list of previews that are
|
||||
* compatible with the 'mail.Preview' template.
|
||||
*/
|
||||
_getPreviews: function () {
|
||||
var mailbotPreviews = this.call('mailbot_service', 'getPreviews', this._filter);
|
||||
return this._super.apply(this, arguments).then(function (previews) {
|
||||
return _.union(mailbotPreviews, previews);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Handle the response of the user when prompted whether push notifications
|
||||
* are granted or denied.
|
||||
*
|
||||
* Also refreshes the counter after a response from a push notification
|
||||
* request. This is useful because the counter contains a part for the
|
||||
* OdooBot, and the OdooBot influences the counter by 1 when it requests
|
||||
* for notifications. This should no longer be the case when push
|
||||
* notifications are either granted or denied.
|
||||
*
|
||||
* @private
|
||||
* @param {string} value
|
||||
*/
|
||||
_handleResponseNotificationPermission: function (value) {
|
||||
if (value !== 'granted') {
|
||||
this.call('bus_service', 'sendNotification', _t('Permission denied'),
|
||||
_t('Odoo will not have the permission to send native notifications on this device.'));
|
||||
} else {
|
||||
this.call('bus_service', 'sendNotification', _t('Yay, push notifications are enabled!'),
|
||||
_t('Odoo has now the permission to send you native notifications on this device.'));
|
||||
}
|
||||
this._updateCounter();
|
||||
},
|
||||
/**
|
||||
* Display the browser notification request dialog when the user clicks on
|
||||
* systray's corresponding notification
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_requestNotificationPermission: function () {
|
||||
var def = window.Notification && window.Notification.requestPermission();
|
||||
if (def) {
|
||||
def.then(this._handleResponseNotificationPermission.bind(this));
|
||||
}
|
||||
this.$('.o_mail_navbar_request_permission').slideUp();
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Override so that it handles preview related to OdooBot
|
||||
*
|
||||
* @override
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onClickPreview: function (ev) {
|
||||
var previewID = $(ev.currentTarget).data('preview-id');
|
||||
if (previewID === 'request_notification') {
|
||||
this._requestNotificationPermission();
|
||||
} else {
|
||||
this._super.apply(this, arguments);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Override so that it handles clicking on 'mark as read' similarly to
|
||||
* requesting push notification permission.
|
||||
*
|
||||
* @override
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onClickPreviewMarkAsRead: function (ev) {
|
||||
ev.stopPropagation();
|
||||
var $preview = $(ev.currentTarget).closest('.o_mail_preview');
|
||||
var previewID = $preview.data('preview-id');
|
||||
if (previewID === 'request_notification') {
|
||||
this._requestNotificationPermission();
|
||||
} else {
|
||||
this._super.apply(this, arguments);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,107 @@
|
||||
odoo.define('mail_bot.systray.MessagingMenuTests', function (require) {
|
||||
"use strict";
|
||||
|
||||
var MessagingMenu = require('mail.systray.MessagingMenu');
|
||||
var mailTestUtils = require('mail.testUtils');
|
||||
|
||||
var MailBotService = require('mail_bot.MailBotService');
|
||||
|
||||
var testUtils = require('web.test_utils');
|
||||
|
||||
QUnit.module('mail_bot', {}, function () {
|
||||
QUnit.module('MessagingMenu', {
|
||||
beforeEach: function () {
|
||||
var self = this;
|
||||
|
||||
this.data = {
|
||||
'mail.channel': {
|
||||
fields: {},
|
||||
records: [],
|
||||
},
|
||||
'mail.message': {
|
||||
fields: {},
|
||||
records: [],
|
||||
},
|
||||
};
|
||||
|
||||
// Patch mailbot_service so that it does do not do any RPC, and
|
||||
// the detection of push notifications permissions can be simulated in
|
||||
// the test cases. By default, shows 'OdooBot has a request'
|
||||
this.hasMailbotRequest = true;
|
||||
testUtils.patch(MailBotService, {
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
start: function () {},
|
||||
/**
|
||||
* @override
|
||||
* @returns {boolean}
|
||||
*/
|
||||
hasRequest: function () {
|
||||
return self.hasMailbotRequest;
|
||||
},
|
||||
});
|
||||
|
||||
this.services = _.extend({}, mailTestUtils.getMailServices(), {
|
||||
mailbot_service: MailBotService
|
||||
});
|
||||
},
|
||||
afterEach: function () {
|
||||
// unpatch MailBotService
|
||||
testUtils.unpatch(MailBotService);
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test('messaging menu widget: rendering with OdooBot has a request', function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
var messagingMenu = new MessagingMenu();
|
||||
testUtils.addMockEnvironment(messagingMenu, {
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
|
||||
assert.strictEqual(messagingMenu.$('.o_notification_counter').length, 1,
|
||||
"should display a notification counter next to the messaging menu");
|
||||
assert.strictEqual(messagingMenu.$('.o_notification_counter').text(), '1',
|
||||
"should display a counter of '1' next to the messaging menu");
|
||||
|
||||
messagingMenu.$('.dropdown-toggle').click();
|
||||
assert.strictEqual(messagingMenu.$('.o_preview_info').length, 1,
|
||||
"should display a preview in the messaging menu");
|
||||
assert.strictEqual(messagingMenu.$('.o_preview_name').text().trim(),
|
||||
'OdooBot has a request',
|
||||
"preview should display that OdooBot has a request");
|
||||
assert.strictEqual(messagingMenu.$('.o_preview_counter').text().replace(/\s/g, ''),
|
||||
'(1)', "should display an counter of '1' next to the preview");
|
||||
|
||||
messagingMenu.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('messaging menu widget: rendering without OdooBot has a request', function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
this.hasMailbotRequest = false;
|
||||
|
||||
var messagingMenu = new MessagingMenu();
|
||||
testUtils.addMockEnvironment(messagingMenu, {
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
|
||||
assert.strictEqual(messagingMenu.$('.o_notification_counter').length, 1,
|
||||
"should display a notification counter next to the messaging menu");
|
||||
assert.strictEqual(messagingMenu.$('.o_notification_counter').text(), '0',
|
||||
"should display a counter of '0' next to the messaging menu");
|
||||
messagingMenu.$('.dropdown-toggle').click();
|
||||
assert.strictEqual(messagingMenu.$('.o_preview_info').length, 0,
|
||||
"should display no preview in the messaging menu");
|
||||
|
||||
messagingMenu.destroy();
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
@@ -4,6 +4,12 @@
|
||||
<template id="assets_backend" name="mailbot assets" inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<script type="text/javascript" src="/mail_bot/static/src/js/mailbot_service.js"></script>
|
||||
<script type="text/javascript" src="/mail_bot/static/src/js/systray_messaging_menu.js"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
<template id="qunit_suite" name="mail_tests" inherit_id="web.qunit_suite">
|
||||
<xpath expr="//t[@t-set='head']" position="inside">
|
||||
<script type="text/javascript" src="/mail_bot/static/tests/systray_messaging_menu_tests.js"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
</data>
|
||||
|
||||
Reference in New Issue
Block a user