summaryrefslogtreecommitdiff
path: root/addons/mail/static/src/models/messaging
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/mail/static/src/models/messaging
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/mail/static/src/models/messaging')
-rw-r--r--addons/mail/static/src/models/messaging/messaging.js216
-rw-r--r--addons/mail/static/src/models/messaging/messaging_tests.js66
2 files changed, 282 insertions, 0 deletions
diff --git a/addons/mail/static/src/models/messaging/messaging.js b/addons/mail/static/src/models/messaging/messaging.js
new file mode 100644
index 00000000000..4cd4c22a82f
--- /dev/null
+++ b/addons/mail/static/src/models/messaging/messaging.js
@@ -0,0 +1,216 @@
+odoo.define('mail/static/src/models/messaging/messaging.js', function (require) {
+'use strict';
+
+const { registerNewModel } = require('mail/static/src/model/model_core.js');
+const { attr, many2one, one2one } = require('mail/static/src/model/model_field.js');
+
+function factory(dependencies) {
+
+ class Messaging extends dependencies['mail.model'] {
+
+ /**
+ * @override
+ */
+ delete() {
+ this.env.services['bus_service'].off('window_focus', null, this._handleGlobalWindowFocus);
+ super.delete();
+ }
+
+ //----------------------------------------------------------------------
+ // Public
+ //----------------------------------------------------------------------
+
+ /**
+ * Open the form view of the record with provided id and model.
+ *
+ * @param {Object} param0
+ * @param {integer} param0.id
+ * @param {string} param0.model
+ */
+ openDocument({ id, model }) {
+ this.env.bus.trigger('do-action', {
+ action: {
+ type: 'ir.actions.act_window',
+ res_model: model,
+ views: [[false, 'form']],
+ res_id: id,
+ },
+ });
+ this.messagingMenu.close();
+ }
+
+ /**
+ * Handles redirection to a model and id. Try to handle it in the context
+ * of messaging (e.g. open chat if this is a user), otherwise fallback to
+ * opening form view of record.
+ *
+ * @param {Object} param0
+ * @param {integer} param0.id
+ * @param {string} param0.model
+ * FIXME needs to be tested and maybe refactored (see task-2244279)
+ */
+ async redirect({ id, model }) {
+ if (model === 'mail.channel') {
+ const channel = this.env.models['mail.thread'].find(thread =>
+ thread.id === id &&
+ thread.model === 'mail.channel'
+ );
+ if (!channel || !channel.isPinned) {
+ this.env.models['mail.thread'].joinChannel(id, { autoselect: true });
+ return;
+ }
+ channel.open();
+ } else if (model === 'res.partner') {
+ if (id === this.currentPartner.id) {
+ this.openDocument({
+ model: 'res.partner',
+ id,
+ });
+ return;
+ }
+ const partner = this.env.models['mail.partner'].insert({ id });
+ if (!partner.user) {
+ await this.async(() => partner.checkIsUser());
+ }
+ if (!partner.user) {
+ // partner is not a user, open document instead
+ this.openDocument({
+ model: 'res.partner',
+ id: partner.id,
+ });
+ return;
+ }
+ const chat = partner.correspondentThreads.find(thread =>
+ thread.channel_type === 'chat'
+ );
+ if (!chat) {
+ this.env.models['mail.thread'].createChannel({
+ autoselect: true,
+ partnerId: id,
+ type: 'chat',
+ });
+ return;
+ }
+ chat.open();
+ } else {
+ this.openDocument({
+ model: 'res.partner',
+ id,
+ });
+ }
+ }
+
+ /**
+ * Start messaging and related records.
+ */
+ async start() {
+ this._handleGlobalWindowFocus = this._handleGlobalWindowFocus.bind(this);
+ this.env.services['bus_service'].on('window_focus', null, this._handleGlobalWindowFocus);
+ await this.async(() => this.initializer.start());
+ this.notificationHandler.start();
+ this.update({ isInitialized: true });
+ }
+
+ //----------------------------------------------------------------------
+ // Private
+ //----------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ _handleGlobalWindowFocus() {
+ this.update({ outOfFocusUnreadMessageCounter: 0 });
+ this.env.bus.trigger('set_title_part', {
+ part: '_chat',
+ });
+ }
+
+ }
+
+ Messaging.fields = {
+ attachmentViewer: one2one('mail.attachment_viewer', {
+ autocreate: true,
+ isCausal: true,
+ }),
+ cannedResponses: attr({
+ default: {},
+ }),
+ chatWindowManager: one2one('mail.chat_window_manager', {
+ autocreate: true,
+ inverse: 'messaging',
+ isCausal: true,
+ }),
+ commands: attr({
+ default: {},
+ }),
+ currentPartner: one2one('mail.partner'),
+ currentUser: one2one('mail.user'),
+ device: one2one('mail.device', {
+ autocreate: true,
+ isCausal: true,
+ }),
+ dialogManager: one2one('mail.dialog_manager', {
+ autocreate: true,
+ isCausal: true,
+ }),
+ discuss: one2one('mail.discuss', {
+ autocreate: true,
+ isCausal: true,
+ }),
+ /**
+ * Mailbox History.
+ */
+ history: one2one('mail.thread'),
+ /**
+ * Mailbox Inbox.
+ */
+ inbox: one2one('mail.thread'),
+ initializer: one2one('mail.messaging_initializer', {
+ autocreate: true,
+ inverse: 'messaging',
+ isCausal: true,
+ }),
+ isInitialized: attr({
+ default: false,
+ }),
+ locale: one2one('mail.locale', {
+ autocreate: true,
+ isCausal: true,
+ }),
+ messagingMenu: one2one('mail.messaging_menu', {
+ autocreate: true,
+ inverse: 'messaging',
+ isCausal: true,
+ }),
+ /**
+ * Mailbox Moderation.
+ */
+ moderation: one2one('mail.thread'),
+ notificationGroupManager: one2one('mail.notification_group_manager', {
+ autocreate: true,
+ isCausal: true,
+ }),
+ notificationHandler: one2one('mail.messaging_notification_handler', {
+ autocreate: true,
+ inverse: 'messaging',
+ isCausal: true,
+ }),
+ outOfFocusUnreadMessageCounter: attr({
+ default: 0,
+ }),
+ partnerRoot: many2one('mail.partner'),
+ publicPartner: many2one('mail.partner'),
+ /**
+ * Mailbox Starred.
+ */
+ starred: one2one('mail.thread'),
+ };
+
+ Messaging.modelName = 'mail.messaging';
+
+ return Messaging;
+}
+
+registerNewModel('mail.messaging', factory);
+
+});
diff --git a/addons/mail/static/src/models/messaging/messaging_tests.js b/addons/mail/static/src/models/messaging/messaging_tests.js
new file mode 100644
index 00000000000..11a7b1c5779
--- /dev/null
+++ b/addons/mail/static/src/models/messaging/messaging_tests.js
@@ -0,0 +1,66 @@
+odoo.define('mail/static/src/models/messaging/messaging_tests.js', function (require) {
+'use strict';
+
+const {
+ afterEach: utilsAfterEach,
+ beforeEach: utilsBeforeEach,
+ start: utilsStart,
+} = require('mail/static/src/utils/test_utils.js');
+
+QUnit.module('mail', {}, function () {
+QUnit.module('models', {}, function () {
+QUnit.module('messaging', {}, function () {
+QUnit.module('messaging_tests.js', {
+ beforeEach() {
+ utilsBeforeEach(this);
+
+ this.start = async params => {
+ if (this.widget) {
+ this.widget.destroy();
+ }
+ const { env, widget } = await utilsStart(Object.assign({}, params, {
+ data: this.data,
+ }));
+ this.env = env;
+ this.widget = widget;
+ };
+ },
+ afterEach() {
+ utilsAfterEach(this);
+ this.env = undefined;
+ if (this.widget) {
+ this.widget.destroy();
+ this.widget = undefined;
+ }
+ },
+});
+
+QUnit.test('currentPartner initialized from session', async function (assert) {
+ assert.expect(5);
+
+ await this.start();
+
+ assert.ok(this.env.messaging.currentPartner);
+ assert.strictEqual(
+ this.env.messaging.currentPartner.id,
+ this.env.session.partner_id
+ );
+ assert.strictEqual(
+ this.env.messaging.currentPartner.name,
+ this.env.session.name
+ );
+ assert.strictEqual(
+ this.env.messaging.currentPartner.display_name,
+ this.env.session.partner_display_name
+ );
+ assert.strictEqual(
+ this.env.messaging.currentPartner.user.id,
+ this.env.session.uid
+ );
+});
+
+});
+});
+});
+
+});