summaryrefslogtreecommitdiff
path: root/addons/sms/static/src
diff options
context:
space:
mode:
authorSébastien Theys <seb@odoo.com>2020-06-15 18:12:21 +0000
committerSébastien Theys <seb@odoo.com>2020-06-15 18:12:21 +0000
commit3fea5b2136627c1d7e83b2a5e111952fe3eb10a1 (patch)
tree5eefad07972a87ce4689b83260f981bc87aadad4 /addons/sms/static/src
parent0a82848606151ef60eb6523e9c4c161171f214e7 (diff)
[REF] mail, *: refactor messaging with OWL
This commit is a significant rewriting of client-side discuss, chatter, chat window, and messaging menu using OWL. The behavior should be broadly the same, with some slight functional changes here and there. From a technical standpoint, the code of messaging is mainly organized in 2 main groups of modules: - models, which are logical entities that depict the client-side state of messaging as a whole. - components, which are in charge of displaying information from models. This refactoring also introduces new JS guidelines regarding folder structure (/static) and naming rules for JS modules. Community PR: https://github.com/odoo/odoo/pull/39023 Enterprise PR: https://github.com/odoo/enterprise/pull/6249 Task-1914207 This PR is a collaborative work by Alexandre, Julien, Sébastien and Xavier, with the precious help of Lucas to speed it up towards the end. closes odoo/odoo#39023 Related: odoo/enterprise#6249 Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com> Co-authored-by: Alexandre Kühn <aku@odoo.com> Co-authored-by: Julien Giannone <jgi@odoo.com> Co-authored-by: Lucas Perais <lpe@odoo.com> Co-authored-by: Sébastien Theys <seb@odoo.com> Co-authored-by: Xavier Dubuc <xdu@odoo.com>
Diffstat (limited to 'addons/sms/static/src')
-rw-r--r--addons/sms/static/src/bugfix/bugfix.js10
-rw-r--r--addons/sms/static/src/bugfix/bugfix.scss6
-rw-r--r--addons/sms/static/src/bugfix/bugfix.xml11
-rw-r--r--addons/sms/static/src/bugfix/bugfix_tests.js18
-rw-r--r--addons/sms/static/src/components/message/message.xml20
-rw-r--r--addons/sms/static/src/components/message/message_tests.js187
-rw-r--r--addons/sms/static/src/components/notification_group/notification_group.js27
-rw-r--r--addons/sms/static/src/components/notification_group/notification_group.xml12
-rw-r--r--addons/sms/static/src/components/notification_list/notification_list_notification_group_tests.js312
-rw-r--r--addons/sms/static/src/js/mail_failure.js51
-rw-r--r--addons/sms/static/src/js/message.js32
-rw-r--r--addons/sms/static/src/js/systray_messaging_menu.js80
-rw-r--r--addons/sms/static/src/js/thread_widget.js27
-rw-r--r--addons/sms/static/src/models/message/message.js33
-rw-r--r--addons/sms/static/src/models/notification_group/notification_group.js57
-rw-r--r--addons/sms/static/src/xml/thread.xml8
16 files changed, 693 insertions, 198 deletions
diff --git a/addons/sms/static/src/bugfix/bugfix.js b/addons/sms/static/src/bugfix/bugfix.js
new file mode 100644
index 00000000000..ee604b8b695
--- /dev/null
+++ b/addons/sms/static/src/bugfix/bugfix.js
@@ -0,0 +1,10 @@
+/**
+ * This file allows introducing new JS modules without contaminating other files.
+ * This is useful when bug fixing requires adding such JS modules in stable
+ * versions of Odoo. Any module that is defined in this file should be isolated
+ * in its own file in master.
+ */
+odoo.define('sms/static/src/bugfix/bugfix.js', function (require) {
+'use strict';
+
+});
diff --git a/addons/sms/static/src/bugfix/bugfix.scss b/addons/sms/static/src/bugfix/bugfix.scss
new file mode 100644
index 00000000000..c4272e527b4
--- /dev/null
+++ b/addons/sms/static/src/bugfix/bugfix.scss
@@ -0,0 +1,6 @@
+/**
+* This file allows introducing new styles without contaminating other files.
+* This is useful when bug fixing requires adding new components for instance in
+* stable versions of Odoo. Any style that is defined in this file should be isolated
+* in its own file in master.
+*/
diff --git a/addons/sms/static/src/bugfix/bugfix.xml b/addons/sms/static/src/bugfix/bugfix.xml
new file mode 100644
index 00000000000..c17906f75bb
--- /dev/null
+++ b/addons/sms/static/src/bugfix/bugfix.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<templates xml:space="preserve">
+
+<!--
+ This file allows introducing new static templates without contaminating other files.
+ This is useful when bug fixing requires adding new components for instance in stable
+ versions of Odoo. Any template that is defined in this file should be isolated
+ in its own file in master.
+-->
+
+</templates>
diff --git a/addons/sms/static/src/bugfix/bugfix_tests.js b/addons/sms/static/src/bugfix/bugfix_tests.js
new file mode 100644
index 00000000000..938426c6c60
--- /dev/null
+++ b/addons/sms/static/src/bugfix/bugfix_tests.js
@@ -0,0 +1,18 @@
+odoo.define('sms/static/src/bugfix/bugfix_tests.js', function (require) {
+'use strict';
+
+/**
+ * This file allows introducing new QUnit test modules without contaminating
+ * other test files. This is useful when bug fixing requires adding new
+ * components for instance in stable versions of Odoo. Any test that is defined
+ * in this file should be isolated in its own file in master.
+ */
+QUnit.module('sms', {}, function () {
+QUnit.module('bugfix', {}, function () {
+QUnit.module('bugfix_tests.js', {
+
+});
+});
+});
+
+});
diff --git a/addons/sms/static/src/components/message/message.xml b/addons/sms/static/src/components/message/message.xml
new file mode 100644
index 00000000000..b8b6a18d94a
--- /dev/null
+++ b/addons/sms/static/src/components/message/message.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<templates xml:space="preserve">
+
+ <t t-inherit="mail.Message" t-inherit-mode="extension">
+ <xpath expr="//*[@name='failureIcon']" position="replace">
+ <t t-if="message.message_type === 'sms'">
+ <i class="o_Message_notificationIcon fa fa-mobile"/> SMS
+ </t>
+ <t t-else="">$0</t>
+ </xpath>
+
+ <xpath expr="//*[@name='notificationIcon']" position="replace">
+ <t t-if="message.message_type === 'sms'">
+ <i class="o_Message_notificationIcon fa fa-mobile"/> SMS
+ </t>
+ <t t-else="">$0</t>
+ </xpath>
+ </t>
+
+</templates>
diff --git a/addons/sms/static/src/components/message/message_tests.js b/addons/sms/static/src/components/message/message_tests.js
new file mode 100644
index 00000000000..4c26191a5b3
--- /dev/null
+++ b/addons/sms/static/src/components/message/message_tests.js
@@ -0,0 +1,187 @@
+odoo.define('sms/static/src/components/message/message_tests.js', function (require) {
+'use strict';
+
+const components = {
+ Message: require('mail/static/src/components/message/message.js'),
+};
+const {
+ afterEach: utilsAfterEach,
+ afterNextRender,
+ beforeEach: utilsBeforeEach,
+ start: utilsStart,
+} = require('mail/static/src/utils/test_utils.js');
+
+const Bus = require('web.Bus');
+
+QUnit.module('sms', {}, function () {
+QUnit.module('components', {}, function () {
+QUnit.module('message', {}, function () {
+QUnit.module('message_tests.js', {
+ beforeEach() {
+ utilsBeforeEach(this);
+
+ this.createMessageComponent = async message => {
+ const MessageComponent = components.Message;
+ MessageComponent.env = this.env;
+ this.component = new MessageComponent(null, {
+ messageLocalId: message.localId,
+ });
+ delete MessageComponent.env;
+ await this.component.mount(this.widget.el);
+ };
+
+ this.start = async params => {
+ let { env, widget } = await utilsStart(Object.assign({}, params, {
+ data: this.data,
+ }));
+ this.env = env;
+ this.widget = widget;
+ };
+ },
+ afterEach() {
+ utilsAfterEach(this);
+ if (this.component) {
+ // The component must be destroyed before the widget, because the
+ // widget might destroy the models before destroying the component,
+ // and the Message component is relying on messaging.
+ this.component.destroy();
+ }
+ if (this.widget) {
+ this.widget.destroy();
+ }
+ this.env = undefined;
+ },
+});
+
+QUnit.test('Notification Sent', async function (assert) {
+ assert.expect(9);
+
+ await this.start();
+ const message = this.env.models['mail.message'].create({
+ id: 10,
+ message_type: 'sms',
+ notifications: [['insert', {
+ id: 11,
+ notification_status: 'sent',
+ notification_type: 'sms',
+ partner: [['insert', { id: 12, name: "Someone" }]],
+ }]],
+ });
+ await this.createMessageComponent(message);
+
+ assert.containsOnce(
+ document.body,
+ '.o_Message',
+ "should display a message component"
+ );
+ assert.containsOnce(
+ document.body,
+ '.o_Message_notificationIconContainer',
+ "should display the notification icon container"
+ );
+ assert.containsOnce(
+ document.body,
+ '.o_Message_notificationIcon',
+ "should display the notification icon"
+ );
+ assert.hasClass(
+ document.querySelector('.o_Message_notificationIcon'),
+ 'fa-mobile',
+ "icon should represent sms"
+ );
+
+ await afterNextRender(() => {
+ document.querySelector('.o_Message_notificationIconContainer').click();
+ });
+ assert.containsOnce(
+ document.body,
+ '.o_NotificationPopover',
+ "notification popover should be open"
+ );
+ assert.containsOnce(
+ document.body,
+ '.o_NotificationPopover_notificationIcon',
+ "popover should have one icon"
+ );
+ assert.hasClass(
+ document.querySelector('.o_NotificationPopover_notificationIcon'),
+ 'fa-check',
+ "popover should have the sent icon"
+ );
+ assert.containsOnce(
+ document.body,
+ '.o_NotificationPopover_notificationPartnerName',
+ "popover should have the partner name"
+ );
+ assert.strictEqual(
+ document.querySelector('.o_NotificationPopover_notificationPartnerName').textContent.trim(),
+ "Someone",
+ "partner name should be correct"
+ );
+});
+
+QUnit.test('Notification Error', async function (assert) {
+ assert.expect(8);
+
+ const bus = new Bus();
+ bus.on('do-action', null, payload => {
+ assert.step('do_action');
+ assert.strictEqual(
+ payload.action,
+ 'sms.sms_resend_action',
+ "action should be the one to resend sms"
+ );
+ assert.strictEqual(
+ payload.options.additional_context.default_mail_message_id,
+ 10,
+ "action should have correct message id"
+ );
+ });
+
+ await this.start({ env: { bus } });
+ const message = this.env.models['mail.message'].create({
+ id: 10,
+ message_type: 'sms',
+ notifications: [['insert', {
+ id: 11,
+ notification_status: 'exception',
+ notification_type: 'sms',
+ }]],
+ });
+ await this.createMessageComponent(message);
+
+ assert.containsOnce(
+ document.body,
+ '.o_Message',
+ "should display a message component"
+ );
+ assert.containsOnce(
+ document.body,
+ '.o_Message_notificationIconContainer',
+ "should display the notification icon container"
+ );
+ assert.containsOnce(
+ document.body,
+ '.o_Message_notificationIcon',
+ "should display the notification icon"
+ );
+ assert.hasClass(
+ document.querySelector('.o_Message_notificationIcon'),
+ 'fa-mobile',
+ "icon should represent sms"
+ );
+
+ await afterNextRender(() => {
+ document.querySelector('.o_Message_notificationIconContainer').click();
+ });
+ assert.verifySteps(
+ ['do_action'],
+ "should do an action to display the resend sms dialog"
+ );
+});
+
+});
+});
+});
+
+});
diff --git a/addons/sms/static/src/components/notification_group/notification_group.js b/addons/sms/static/src/components/notification_group/notification_group.js
new file mode 100644
index 00000000000..053fedc5bd2
--- /dev/null
+++ b/addons/sms/static/src/components/notification_group/notification_group.js
@@ -0,0 +1,27 @@
+odoo.define('sms/static/src/components/notification_group/notification_group.js', function (require) {
+'use strict';
+
+const components = {
+ NotificationGroup: require('mail/static/src/components/notification_group/notification_group.js'),
+};
+
+const { patch } = require('web.utils');
+
+patch(components.NotificationGroup, 'sms/static/src/components/notification_group/notification_group.js', {
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ /**
+ * @override
+ */
+ image() {
+ if (this.group.notification_type === 'sms') {
+ return '/sms/static/img/sms_failure.svg';
+ }
+ return this._super(...arguments);
+ },
+});
+
+});
diff --git a/addons/sms/static/src/components/notification_group/notification_group.xml b/addons/sms/static/src/components/notification_group/notification_group.xml
new file mode 100644
index 00000000000..c5f5a8db5dc
--- /dev/null
+++ b/addons/sms/static/src/components/notification_group/notification_group.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<templates xml:space="preserve">
+
+ <t t-inherit="mail.NotificationGroup" t-inherit-mode="extension">
+ <xpath expr="//*[hasclass('o_NotificationGroup_inlineText')]" position="inside">
+ <t t-if="group.notification_type === 'sms'">
+ An error occurred when sending an SMS.
+ </t>
+ </xpath>
+ </t>
+
+</templates>
diff --git a/addons/sms/static/src/components/notification_list/notification_list_notification_group_tests.js b/addons/sms/static/src/components/notification_list/notification_list_notification_group_tests.js
new file mode 100644
index 00000000000..5f46f57d3ef
--- /dev/null
+++ b/addons/sms/static/src/components/notification_list/notification_list_notification_group_tests.js
@@ -0,0 +1,312 @@
+odoo.define('sms/static/src/components/notification_list/notification_list_notification_group_tests.js', function (require) {
+'use strict';
+
+const components = {
+ NotificationList: require('mail/static/src/components/notification_list/notification_list.js'),
+};
+
+const {
+ afterEach: utilsAfterEach,
+ afterNextRender,
+ beforeEach: utilsBeforeEach,
+ start: utilsStart,
+} = require('mail/static/src/utils/test_utils.js');
+
+const Bus = require('web.Bus');
+
+QUnit.module('sms', {}, function () {
+QUnit.module('components', {}, function () {
+QUnit.module('notification_list', {}, function () {
+QUnit.module('notification_list_notification_group_tests.js', {
+ beforeEach() {
+ utilsBeforeEach(this);
+
+ /**
+ * @param {Object} param0
+ * @param {string} [param0.filter='all']
+ */
+ this.createNotificationListComponent = async ({ filter = 'all' } = {}) => {
+ const NotificationListComponent = components.NotificationList;
+ NotificationListComponent.env = this.env;
+ this.component = new NotificationListComponent(null, { filter });
+ await afterNextRender(() => this.component.mount(this.widget.el));
+ };
+
+ this.start = async params => {
+ let { env, widget } = await utilsStart(Object.assign({}, params, {
+ data: this.data,
+ }));
+ this.env = env;
+ this.widget = widget;
+ };
+ },
+ afterEach() {
+ utilsAfterEach(this);
+ if (this.component) {
+ this.component.destroy();
+ this.component = undefined;
+ }
+ if (this.widget) {
+ this.widget.destroy();
+ this.widget = undefined;
+ }
+ this.env = undefined;
+ delete components.NotificationList.env;
+ },
+});
+
+QUnit.test('mark as read', async function (assert) {
+ assert.expect(6);
+
+ this.data.initMessaging.mail_failures = [{
+ date: moment.utc().format("YYYY-MM-DD HH:mm:ss"),
+ id: 11,
+ message_type: 'sms',
+ model: 'mail.channel',
+ notifications: [{
+ failure_type: 'sms_credit',
+ id: 21,
+ notification_status: 'exception',
+ notification_type: 'sms',
+ partner_id: [41, "Someone"],
+ }],
+ res_id: 31,
+ res_model_name: "Channel",
+ }];
+ const bus = new Bus();
+ bus.on('do-action', null, payload => {
+ assert.step('do_action');
+ assert.strictEqual(
+ payload.action,
+ 'sms.sms_cancel_action',
+ "action should be the one to cancel sms"
+ );
+ assert.strictEqual(
+ payload.options.additional_context.default_model,
+ 'mail.channel',
+ "action should have the group model as default_model"
+ );
+ assert.strictEqual(
+ payload.options.additional_context.unread_counter,
+ 1,
+ "action should have the group notification length as unread_counter"
+ );
+ });
+
+ await this.start({ env: { bus } });
+ await this.createNotificationListComponent();
+
+ assert.containsOnce(
+ document.body,
+ '.o_NotificationGroup_markAsRead',
+ "should have 1 mark as read button"
+ );
+
+ document.querySelector('.o_NotificationGroup_markAsRead').click();
+ assert.verifySteps(
+ ['do_action'],
+ "should do an action to display the cancel sms dialog"
+ );
+});
+
+QUnit.test('notifications grouped by notification_type', async function (assert) {
+ assert.expect(11);
+
+ this.data.initMessaging.mail_failures = [{
+ date: moment.utc().format("YYYY-MM-DD HH:mm:ss"),
+ id: 11,
+ message_type: 'email', // key element of this test: different type
+ model: 'res.partner', // key element of this test: same model (and not `mail.channel``)
+ notifications: [{
+ failure_type: 'SMTP',
+ id: 21,
+ notification_status: 'exception',
+ notification_type: 'email', // key element of this test: different type
+ partner_id: [41, "Someone"],
+ }],
+ res_id: 31, // key element of this test: same res_id
+ res_model_name: "Partner",
+ }, {
+ date: moment.utc().format("YYYY-MM-DD HH:mm:ss"),
+ id: 12,
+ message_type: 'sms', // key element of this test: different type
+ model: 'res.partner', // key element of this test: same model (and not `mail.channel``)
+ notifications: [{
+ failure_type: 'sms_credit',
+ id: 22,
+ notification_status: 'exception',
+ notification_type: 'sms', // key element of this test: different type
+ partner_id: [42, "Someone else"],
+ }],
+ res_id: 31, // key element of this test: same res_id
+ res_model_name: "Partner",
+ }];
+
+ await this.start();
+ await this.createNotificationListComponent();
+
+ assert.containsN(
+ document.body,
+ '.o_NotificationGroup',
+ 2,
+ "should have 2 notifications group"
+ );
+ const groups = document.querySelectorAll('.o_NotificationGroup');
+ assert.containsOnce(
+ groups[0],
+ '.o_NotificationGroup_name',
+ "should have 1 group name in first group"
+ );
+ assert.strictEqual(
+ groups[0].querySelector('.o_NotificationGroup_name').textContent,
+ "Partner",
+ "should have model name as group name"
+ );
+ assert.containsOnce(
+ groups[0],
+ '.o_NotificationGroup_counter',
+ "should have 1 group counter in first group"
+ );
+ assert.strictEqual(
+ groups[0].querySelector('.o_NotificationGroup_counter').textContent.trim(),
+ "(1)",
+ "should have 1 notification in first group"
+ );
+ assert.strictEqual(
+ groups[0].querySelector('.o_NotificationGroup_inlineText').textContent.trim(),
+ "An error occurred when sending an email.",
+ "should have the group text corresponding to email"
+ );
+ assert.containsOnce(
+ groups[1],
+ '.o_NotificationGroup_name',
+ "should have 1 group name in second group"
+ );
+ assert.strictEqual(
+ groups[1].querySelector('.o_NotificationGroup_name').textContent,
+ "Partner",
+ "should have second model name as group name"
+ );
+ assert.containsOnce(
+ groups[1],
+ '.o_NotificationGroup_counter',
+ "should have 1 group counter in second group"
+ );
+ assert.strictEqual(
+ groups[1].querySelector('.o_NotificationGroup_counter').textContent.trim(),
+ "(1)",
+ "should have 1 notification in second group"
+ );
+ assert.strictEqual(
+ groups[1].querySelector('.o_NotificationGroup_inlineText').textContent.trim(),
+ "An error occurred when sending an SMS.",
+ "should have the group text corresponding to sms"
+ );
+});
+
+QUnit.test('grouped notifications by document model', async function (assert) {
+ // If all failures linked to a document model refers to different documents,
+ // a single notification should group all failures that are linked to this
+ // document model.
+ assert.expect(12);
+
+ this.data.initMessaging.mail_failures = [{
+ date: moment.utc().format("YYYY-MM-DD HH:mm:ss"),
+ id: 11,
+ message_type: 'sms',
+ model: 'res.partner', // key element of this test: same model
+ notifications: [{
+ failure_type: 'sms_credit',
+ id: 21,
+ notification_status: 'exception',
+ notification_type: 'sms',
+ partner_id: [41, "Someone"],
+ }],
+ res_id: 31, // key element of this test: a different res_id
+ res_model_name: "Partner",
+ }, {
+ date: moment.utc().format("YYYY-MM-DD HH:mm:ss"),
+ id: 12,
+ message_type: 'sms',
+ model: 'res.partner', // key element of this test: same model
+ notifications: [{
+ failure_type: 'sms_credit',
+ id: 22,
+ notification_status: 'exception',
+ notification_type: 'sms',
+ partner_id: [42, "Someone else"],
+ }],
+ res_id: 32, // key element of this test: a different res_id
+ res_model_name: "Partner",
+ }];
+ const bus = new Bus();
+ bus.on('do-action', null, payload => {
+ assert.step('do_action');
+ assert.strictEqual(
+ payload.action.name,
+ "SMS Failures",
+ "action should have 'SMS Failures' as name",
+ );
+ assert.strictEqual(
+ payload.action.type,
+ 'ir.actions.act_window',
+ "action should have the type act_window"
+ );
+ assert.strictEqual(
+ payload.action.view_mode,
+ 'kanban,list,form',
+ "action should have 'kanban,list,form' as view_mode"
+ );
+ assert.strictEqual(
+ JSON.stringify(payload.action.views),
+ JSON.stringify([[false, 'kanban'], [false, 'list'], [false, 'form']]),
+ "action should have correct views"
+ );
+ assert.strictEqual(
+ payload.action.target,
+ 'current',
+ "action should have 'current' as target"
+ );
+ assert.strictEqual(
+ payload.action.res_model,
+ 'res.partner',
+ "action should have the group model as res_model"
+ );
+ assert.strictEqual(
+ JSON.stringify(payload.action.domain),
+ JSON.stringify([['message_has_sms_error', '=', true]]),
+ "action should have 'message_has_sms_error' as domain"
+ );
+ });
+
+ await this.start({ env: { bus } });
+ await this.createNotificationListComponent();
+
+ assert.containsOnce(
+ document.body,
+ '.o_NotificationGroup',
+ "should have 1 notification group"
+ );
+ assert.containsOnce(
+ document.body,
+ '.o_NotificationGroup_counter',
+ "should have 1 group counter"
+ );
+ assert.strictEqual(
+ document.querySelector('.o_NotificationGroup_counter').textContent.trim(),
+ "(2)",
+ "should have 2 notifications in the group"
+ );
+
+ document.querySelector('.o_NotificationGroup').click();
+ assert.verifySteps(
+ ['do_action'],
+ "should do an action to display the related records"
+ );
+});
+
+});
+});
+});
+
+});
diff --git a/addons/sms/static/src/js/mail_failure.js b/addons/sms/static/src/js/mail_failure.js
deleted file mode 100644
index 4df13760f8c..00000000000
--- a/addons/sms/static/src/js/mail_failure.js
+++ /dev/null
@@ -1,51 +0,0 @@
-odoo.define('sms.model.MailFailure', function (require) {
-'use strict';
-
-var MailFailure = require('mail.model.MailFailure');
-var core = require('web.core');
-var _t = core._t;
-
-MailFailure.include({
-
- //--------------------------------------------------------------------------
- // Public
- //--------------------------------------------------------------------------
-
- /**
- * @override
- */
- getPreview: function () {
- var preview = this._super.apply(this, arguments);
- if (this.getMessageType() === 'sms') {
- _.extend(preview, {
- id: 'sms_failure',
- });
- }
- return preview;
- },
-
- //--------------------------------------------------------------------------
- // Private
- //--------------------------------------------------------------------------
-
- /**
- * @override
- */
- _getPreviewBody() {
- if (this.getMessageType() === 'sms') {
- return _t("An error occurred when sending an SMS.");
- }
- return this._super(...arguments);
- },
- /**
- * @override
- */
- _getPreviewImage() {
- if (this.getMessageType() === 'sms') {
- return '/sms/static/img/sms_failure.svg';
- }
- return this._super(...arguments);
- },
-});
-
-});
diff --git a/addons/sms/static/src/js/message.js b/addons/sms/static/src/js/message.js
deleted file mode 100644
index 76cc49f266f..00000000000
--- a/addons/sms/static/src/js/message.js
+++ /dev/null
@@ -1,32 +0,0 @@
-odoo.define('sms.model.Message', function (require) {
-"use strict";
-
-const { _t } = require('web.core');
-
-var Message = require('mail.model.Message');
-
-Message.include({
- //--------------------------------------------------------------------------
- // Public
- //--------------------------------------------------------------------------
-
- /**
- * @override
- */
- getNotificationIcon() {
- if (this.getType() === 'sms') {
- return 'fa fa-mobile';
- }
- return this._super(...arguments);
- },
- /**
- * @override
- */
- getNotificationText() {
- if (this.getType() === 'sms') {
- return _t("SMS");
- }
- return this._super(...arguments);
- },
-});
-});
diff --git a/addons/sms/static/src/js/systray_messaging_menu.js b/addons/sms/static/src/js/systray_messaging_menu.js
deleted file mode 100644
index 4e8a354656d..00000000000
--- a/addons/sms/static/src/js/systray_messaging_menu.js
+++ /dev/null
@@ -1,80 +0,0 @@
-odoo.define('sms.systray.MessagingMenu', function (require) {
-"use strict";
-
-var core = require('web.core');
-var MessagingMenu = require('mail.systray.MessagingMenu');
-
-var _t = core._t;
-
-MessagingMenu.include({
-
- //--------------------------------------------------------------------------
- // Private
- //--------------------------------------------------------------------------
-
- /**
- * Called when clicking on a preview related to an SMS failure.
- *
- * @private
- * @param {$.Element} $target DOM of preview element clicked
- */
- _clickSMSFailurePreview: function ($target) {
- var documentID = $target.data('document-id');
- var documentModel = $target.data('document-model');
- if (documentModel && documentID) {
- this._openDocument(documentModel, documentID);
- } else if (documentModel !== 'mail.channel') {
- // preview of SMS failures grouped to different document of same model
- this.do_action({
- name: _t('SMS Failures'),
- type: 'ir.actions.act_window',
- view_mode: 'kanban,list,form',
- views: [[false, 'kanban'], [false, 'list'], [false, 'form']],
- target: 'current',
- res_model: documentModel,
- domain: [['message_has_sms_error', '=', true]],
- });
- }
- },
-
- //--------------------------------------------------------------------------
- // Handlers
- //--------------------------------------------------------------------------
-
- /**
- * @private
- * @override
- */
- _onClickPreview: function (ev) {
- var $target = $(ev.currentTarget);
- var previewID = $target.data('preview-id');
- if (previewID === 'sms_failure') {
- this._clickSMSFailurePreview($target);
- } else {
- this._super.apply(this, arguments);
- }
- },
- /**
- * @private
- * @override
- */
- _onClickPreviewMarkAsRead: function (ev) {
- ev.stopPropagation();
- var $preview = $(ev.currentTarget).closest('.o_mail_preview');
- var previewID = $preview.data('preview-id');
- if (previewID === 'sms_failure') {
- var documentModel = $preview.data('document-model');
- var unreadCounter = $preview.data('unread-counter');
- this.do_action('sms.sms_cancel_action', {
- additional_context: {
- default_model: documentModel,
- unread_counter: unreadCounter
- }
- });
- } else {
- this._super.apply(this, arguments);
- }
- },
-});
-
-});
diff --git a/addons/sms/static/src/js/thread_widget.js b/addons/sms/static/src/js/thread_widget.js
deleted file mode 100644
index b64d6b064f0..00000000000
--- a/addons/sms/static/src/js/thread_widget.js
+++ /dev/null
@@ -1,27 +0,0 @@
-odoo.define('sms.widget.Thread', function (require) {
-"use strict";
-
-var ThreadWidget = require('mail.widget.Thread');
-
-ThreadWidget.include({
- //--------------------------------------------------------------------------
- // Handlers
- //--------------------------------------------------------------------------
-
- /**
- * @override
- */
- _onClickMessageNotificationError(ev) {
- if ($(ev.currentTarget).data('message-type') === 'sms') {
- var messageID = $(ev.currentTarget).data('message-id');
- this.do_action('sms.sms_resend_action', {
- additional_context: {
- default_mail_message_id: messageID
- }
- });
- } else {
- this._super(...arguments);
- }
- },
-});
-});
diff --git a/addons/sms/static/src/models/message/message.js b/addons/sms/static/src/models/message/message.js
new file mode 100644
index 00000000000..2f468cc05c7
--- /dev/null
+++ b/addons/sms/static/src/models/message/message.js
@@ -0,0 +1,33 @@
+odoo.define('sms/static/src/models/message/message.js', function (require) {
+'use strict';
+
+const {
+ registerInstancePatchModel,
+} = require('mail/static/src/model/model_core.js');
+
+registerInstancePatchModel('mail.message', 'sms/static/src/models/message/message.js', {
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ /**
+ * @override
+ */
+ openResendAction() {
+ if (this.message_type === 'sms') {
+ this.env.bus.trigger('do-action', {
+ action: 'sms.sms_resend_action',
+ options: {
+ additional_context: {
+ default_mail_message_id: this.id,
+ },
+ },
+ });
+ } else {
+ this._super(...arguments);
+ }
+ },
+});
+
+});
diff --git a/addons/sms/static/src/models/notification_group/notification_group.js b/addons/sms/static/src/models/notification_group/notification_group.js
new file mode 100644
index 00000000000..151d794b86c
--- /dev/null
+++ b/addons/sms/static/src/models/notification_group/notification_group.js
@@ -0,0 +1,57 @@
+odoo.define('sms/static/src/models/notification_group/notification_group.js', function (require) {
+'use strict';
+
+const {
+ registerInstancePatchModel,
+} = require('mail/static/src/model/model_core.js');
+
+registerInstancePatchModel('mail.notification_group', 'sms/static/src/models/notification_group/notification_group.js', {
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ /**
+ * @override
+ */
+ openCancelAction() {
+ if (this.notification_type === 'sms') {
+ this.env.bus.trigger('do-action', {
+ action: 'sms.sms_cancel_action',
+ options: {
+ additional_context: {
+ default_model: this.res_model,
+ unread_counter: this.notifications.length,
+ },
+ },
+ });
+ }
+ return this._super(...arguments);
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * @override
+ */
+ _openDocuments() {
+ if (this.notification_type === 'sms') {
+ this.env.bus.trigger('do-action', {
+ action: {
+ name: this.env._t("SMS Failures"),
+ type: 'ir.actions.act_window',
+ view_mode: 'kanban,list,form',
+ views: [[false, 'kanban'], [false, 'list'], [false, 'form']],
+ target: 'current',
+ res_model: this.res_model,
+ domain: [['message_has_sms_error', '=', true]],
+ },
+ });
+ }
+ return this._super(...arguments);
+ },
+});
+
+});
diff --git a/addons/sms/static/src/xml/thread.xml b/addons/sms/static/src/xml/thread.xml
deleted file mode 100644
index 56133864767..00000000000
--- a/addons/sms/static/src/xml/thread.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<template id="template" xml:space="preserve">
- <t t-inherit="mail.widget.Thread.Message.MailTooltip" t-inherit-mode="extension">
- <xpath expr="//span[@name='notification_status']" position="inside">
- <i t-if="notification.notification_status === 'outgoing'" class='fa fa-clock-o' title="Awaiting Dispatch" role="img" aria-label="Awaiting Dispatch"/>
- </xpath>
- </t>
-</template>