diff options
| author | Christophe Simonis <chs@odoo.com> | 2018-11-16 19:30:20 +0100 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2018-11-16 19:30:20 +0100 |
| commit | 6faad524cf5e4db02855cb213277c40aee14c42a (patch) | |
| tree | 383c984dc1461a03481baa9fbdce8c156ca97e2e /addons/mail/static | |
| parent | 3657dc77c2ddb4275f07d1271b93e7f25e09913a (diff) | |
| parent | bc744a1da46efda6f1eb5c341f2fa5df30c9c7ad (diff) | |
[MERGE] forward port branch 12.0 up to bc744a1da46
Diffstat (limited to 'addons/mail/static')
14 files changed, 495 insertions, 77 deletions
diff --git a/addons/mail/static/src/js/composers/basic_composer.js b/addons/mail/static/src/js/composers/basic_composer.js index a6cdb39e2de..8a533cd4515 100644 --- a/addons/mail/static/src/js/composers/basic_composer.js +++ b/addons/mail/static/src/js/composers/basic_composer.js @@ -211,7 +211,8 @@ var BasicComposer = Widget.extend({ * displayed to the user. If none of them match, then it will fetch for more * partner suggestions (@see _mentionFetchPartners). * - * @param {$.Deferred<Object[]>} prefetchedPartners + * @param {$.Deferred<Object[]>} prefetchedPartners list of list of + * prefetched partners. */ mentionSetPrefetchedPartners: function (prefetchedPartners) { this._mentionPrefetchedPartners = prefetchedPartners; @@ -302,21 +303,23 @@ var BasicComposer = Widget.extend({ */ _mentionFetchPartners: function (search) { var self = this; - return $.when(this._mentionPrefetchedPartners).then(function (partners) { + return $.when(this._mentionPrefetchedPartners).then(function (prefetchedPartners) { // filter prefetched partners with the given search string var suggestions = []; var limit = self.options.mentionFetchLimit; var searchRegexp = new RegExp(_.str.escapeRegExp(mailUtils.unaccent(search)), 'i'); - if (limit > 0) { - var filteredPartners = _.filter(partners, function (partner) { - return partner.email && searchRegexp.test(partner.email) || - partner.name && searchRegexp.test(mailUtils.unaccent(partner.name)); - }); - if (filteredPartners.length) { - suggestions.push(filteredPartners.slice(0, limit)); - limit -= filteredPartners.length; + _.each(prefetchedPartners, function (partners) { + if (limit > 0) { + var filteredPartners = _.filter(partners, function (partner) { + return partner.email && searchRegexp.test(partner.email) || + partner.name && searchRegexp.test(mailUtils.unaccent(partner.name)); + }); + if (filteredPartners.length) { + suggestions.push(filteredPartners.slice(0, limit)); + limit -= filteredPartners.length; + } } - } + }); if (!suggestions.length && !self.options.mentionPartnersRestricted) { // no result found among prefetched partners, fetch other suggestions suggestions = self._mentionFetchThrottled( diff --git a/addons/mail/static/src/js/models/messages/message.js b/addons/mail/static/src/js/models/messages/message.js index c733b74f347..4342b1e244a 100644 --- a/addons/mail/static/src/js/models/messages/message.js +++ b/addons/mail/static/src/js/models/messages/message.js @@ -262,6 +262,7 @@ var Message = AbstractMessage.extend(Mixins.EventDispatcherMixin, ServicesMixin documentID: this.getDocumentID(), id: id, imageSRC: this._getModuleIcon() || this.getAvatarSource(), + messageID: this.getID(), status: this.status, title: title, }; @@ -457,6 +458,9 @@ var Message = AbstractMessage.extend(Mixins.EventDispatcherMixin, ServicesMixin */ setModerationStatus: function (newModerationStatus, options) { var self = this; + if (newModerationStatus === this._moderationStatus) { + return; + } this._moderationStatus = newModerationStatus; if (newModerationStatus === 'accepted' && options) { _.each(options.additionalThreadIDs, function (threadID) { diff --git a/addons/mail/static/src/js/models/threads/channel.js b/addons/mail/static/src/js/models/threads/channel.js index 695275e799e..808e8b7fbca 100644 --- a/addons/mail/static/src/js/models/threads/channel.js +++ b/addons/mail/static/src/js/models/threads/channel.js @@ -179,7 +179,8 @@ var Channel = SearchableThread.extend(ThreadTypingMixin, { /** * Get listeners of a channel * - * @returns {$.Promise<Object[]>} resolved with list of channel listeners + * @returns {$.Promise<Array<Object[]>>} resolved with list of list of + * channel listeners. */ getMentionPartnerSuggestions: function () { var self = this; @@ -193,7 +194,7 @@ var Channel = SearchableThread.extend(ThreadTypingMixin, { }) .then(function (members) { self._members = members; - return members; + return [members]; }); } return this._membersDef; diff --git a/addons/mail/static/src/js/models/threads/livechat.js b/addons/mail/static/src/js/models/threads/livechat.js index b7235e7bc0e..f4cb58ebad3 100644 --- a/addons/mail/static/src/js/models/threads/livechat.js +++ b/addons/mail/static/src/js/models/threads/livechat.js @@ -37,7 +37,8 @@ var Livechat = TwoUserChannel.extend({ * display of a user that is typing. * * @override - * @returns {$.Promise<Object[]>} resolved with list of livechat members + * @returns {$.Promise<Array<Object[]>>} resolved with list of list of + * livechat members. */ getMentionPartnerSuggestions: function () { var self = this; @@ -49,7 +50,7 @@ var Livechat = TwoUserChannel.extend({ name: self._WEBSITE_USER_NAME, }); } - return self._members; + return [self._members]; }); }, /** diff --git a/addons/mail/static/src/js/models/threads/mailbox.js b/addons/mail/static/src/js/models/threads/mailbox.js index 28dbc4b7163..82d65bdd6cc 100644 --- a/addons/mail/static/src/js/models/threads/mailbox.js +++ b/addons/mail/static/src/js/models/threads/mailbox.js @@ -46,28 +46,6 @@ var Mailbox = SearchableThread.extend({ this._mailboxCounter = Math.max(this._mailboxCounter - num, 0); }, /** - * Override so that there are options to filter messages based on document - * model and ID. - * - * @override - * @param {Object} [options] - * @param {string} [options.documentModel] model of the document that the - * local messages of inbox must be linked to. - * @param {integer} [options.documentID] ID of the document that the local - * messages of inbox must be linked to. - * @returns {mail.model.Message[]} - */ - getMessages: function (options) { - var messages = this._super.apply(this, arguments); - if (options.documentModel && options.documentID) { - return _.filter(messages, function (message) { - return message.getDocumentModel() === options.documentModel && - message.getDocumentID() === options.documentID; - }); - } - return messages; - }, - /** * Get the mailbox counter of this mailbox. * * @returns {integer} @@ -89,31 +67,40 @@ var Mailbox = SearchableThread.extend({ return this.fetchMessages().then(function (messages) { // pick only last message of chatter // items = list of objects - // { unreadCounter: integer, message: mail.model.Message } + // { + // unreadCounter: {integer}, + // message: {mail.model.Message}, + // messageIDs: {integer[]}, + // } var items = []; _.each(messages, function (message) { var unreadCounter = 1; + var messageIDs = [message.getID()]; var similarItem = _.find(items, function (item) { return self._areMessagesFromSameDocumentThread(item.message, message) || self._areMessagesFromSameChannel(item.message, message); }); if (similarItem) { unreadCounter = similarItem.unreadCounter + 1; + messageIDs = similarItem.messageIDs.concat(messageIDs); var index = _.findIndex(items, similarItem); items[index] = { unreadCounter: unreadCounter, message: message, + messageIDs: messageIDs }; } else { items.push({ unreadCounter: unreadCounter, message: message, + messageIDs: messageIDs, }); } }); return _.map(items, function (item) { return _.extend(item.message.getPreview(), { unreadCounter: item.unreadCounter, + messageIDs: item.messageIDs, }); }); }); diff --git a/addons/mail/static/src/js/models/threads/thread.js b/addons/mail/static/src/js/models/threads/thread.js index c9dda28dd93..8c2beb8bbfa 100644 --- a/addons/mail/static/src/js/models/threads/thread.js +++ b/addons/mail/static/src/js/models/threads/thread.js @@ -15,7 +15,8 @@ var ServicesMixin = require('web.ServicesMixin'); * In particular, channels and mailboxes are two different kinds of threads. */ var Thread = AbstractThread.extend(ServicesMixin, { - + // max number of fetched messages from the server + _FETCH_LIMIT: 30, /** * @override * @param {Object} params @@ -33,8 +34,6 @@ var Thread = AbstractThread.extend(ServicesMixin, { // means that there is no message in this channel. this._previewed = false; this._type = params.data.type || params.data.channel_type; - // max number of fetched messages from the server - this._FETCH_LIMIT = 30; }, //-------------------------------------------------------------------------- @@ -111,7 +110,7 @@ var Thread = AbstractThread.extend(ServicesMixin, { * By default, a thread has not listener. * * @abstract - * @returns {$.Promise<Object[]>} + * @returns {$.Promise<Array<Object[]>>} */ getMentionPartnerSuggestions: function () { return $.when([]); diff --git a/addons/mail/static/src/js/services/mail_manager.js b/addons/mail/static/src/js/services/mail_manager.js index 734f12f0cf3..c21089b7095 100644 --- a/addons/mail/static/src/js/services/mail_manager.js +++ b/addons/mail/static/src/js/services/mail_manager.js @@ -199,7 +199,7 @@ var MailManager = AbstractService.extend({ * Get partners as mentions from a chatter * Typically all employees as partner suggestions. * - * @returns {Array<Object[]>} + * @returns {Array<Array<Object[]>>} */ getMentionPartnerSuggestions: function () { return this._mentionPartnerSuggestions; @@ -1195,8 +1195,8 @@ var MailManager = AbstractService.extend({ * * @private * @param {Object} result data from server on mail/init_messaging rpc - * @param {Object[]} result.mention_partner_suggestions list of suggestions - * with all the employees + * @param {Array<Object[]>} result.mention_partner_suggestions list of + * suggestions. * @param {integer} result.menu_id the menu ID of discuss app */ _updateInternalStateFromServer: function (result) { 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 5a687131504..d86e9e3913b 100644 --- a/addons/mail/static/src/js/systray/systray_messaging_menu.js +++ b/addons/mail/static/src/js/systray/systray_messaging_menu.js @@ -282,7 +282,11 @@ var MessagingMenu = Widget.extend({ // e.g. needaction message of channel var documentID = $target.data('document-id'); var documentModel = $target.data('document-model'); - this._openDocument(documentModel, documentID); + if (!documentModel) { + this._openDiscuss('mailbox_inbox'); + } else { + this._openDocument(documentModel, documentID); + } } else { // preview of thread this.call('mail_service', 'openThread', previewID); @@ -300,19 +304,11 @@ var MessagingMenu = Widget.extend({ var thread; var $preview = $(ev.currentTarget).closest('.o_mail_preview'); var previewID = $preview.data('preview-id'); - var documentModel = $preview.data('document-model'); if (previewID === 'mailbox_inbox') { - var documentID = $preview.data('document-id'); - var inbox = this.call('mail_service', 'getMailbox', 'inbox'); - var messages = inbox.getMessages({ - documentModel: documentModel, - documentID: documentID, - }); - var messageIDs = _.map(messages, function (message) { - return message.getID(); - }); + var messageIDs = [].concat($preview.data('message-ids')); this.call('mail_service', 'markMessagesAsRead', messageIDs); } else if (previewID === 'mail_failure') { + var documentModel = $preview.data('document-model'); var unreadCounter = $preview.data('unread-counter'); this.do_action('mail.mail_resend_cancel_action', { additional_context: { diff --git a/addons/mail/static/src/js/thread_windows/abstract_thread_window.js b/addons/mail/static/src/js/thread_windows/abstract_thread_window.js index f6ba0ccecca..716b86400be 100644 --- a/addons/mail/static/src/js/thread_windows/abstract_thread_window.js +++ b/addons/mail/static/src/js/thread_windows/abstract_thread_window.js @@ -79,7 +79,6 @@ var AbstractThreadWindow = Widget.extend({ this.$header = this.$('.o_thread_window_header'); this._threadWidget = new ThreadWidget(this, { - displayDocumentLinks: false, displayMarkAsRead: false, displayStars: this.options.displayStars, }); diff --git a/addons/mail/static/src/xml/discuss.xml b/addons/mail/static/src/xml/discuss.xml index a09b7a6f754..9d97de471ce 100644 --- a/addons/mail/static/src/xml/discuss.xml +++ b/addons/mail/static/src/xml/discuss.xml @@ -267,10 +267,11 @@ @param {string} [preview.title] @param {string} [preview.status] @param {integer} [preview.unreadCounter] + @param {integer[]} [preview.messageIDs] --> <t t-name="mail.Preview"> <div t-attf-class="o_mail_preview #{preview.unreadCounter > 0 ? 'o_preview_unread' : ''}" - t-att-data-preview-id="preview.id" t-att-data-document-id="preview.documentID" t-att-data-document-model="preview.documentModel" t-att-data-unread-counter="preview.unreadCounter"> + t-att-data-preview-id="preview.id" t-att-data-document-id="preview.documentID" t-att-data-document-model="preview.documentModel" t-att-data-unread-counter="preview.unreadCounter" t-att-data-message-ids="preview.messageIDs"> <div t-attf-class="o_mail_preview_image #{preview.documentModel ? 'o_mail_preview_app' : ''}"> <img class="o_mail_preview_image" t-att-src="preview.imageSRC" alt="Preview"/> <i t-if="preview.status === 'online'" class="o_mail_user_status o_user_online fa fa-circle" title="Online" role="img" aria-label="User is online"/> diff --git a/addons/mail/static/tests/chatter_tests.js b/addons/mail/static/tests/chatter_tests.js index b379bc9050b..4bcce4ab352 100644 --- a/addons/mail/static/tests/chatter_tests.js +++ b/addons/mail/static/tests/chatter_tests.js @@ -2450,6 +2450,124 @@ QUnit.test('chatter: suggested partner auto-follow on message post', function (a form.destroy(); }); +QUnit.test('chatter: mention prefetched partners (followers & employees)', function (assert) { + // Note: employees are in prefeteched partner for mentions in chatter when + // the module hr is installed. + assert.expect(10); + + var followerSuggestions = [{ + id: 1, + name: 'FollowerUser1', + email: 'follower-user1@example.com', + }, { + id: 2, + name: 'FollowerUser2', + email: 'follower-user2@example.com', + }]; + + var nonFollowerSuggestions = [{ + id: 3, + name: 'NonFollowerUser1', + email: 'non-follower-user1@example.com', + }, { + id: 4, + name: 'NonFollowerUser2', + email: 'non-follower-user2@example.com', + }]; + + // link followers + this.data.partner.records[0].message_follower_ids = [10, 20]; + + // prefetched partners + this.data.initMessaging = { + mention_partner_suggestions: [followerSuggestions.concat(nonFollowerSuggestions)], + }; + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + services: this.services, + arch: '<form string="Partners">' + + '<sheet>' + + '<field name="foo"/>' + + '</sheet>' + + '<div class="oe_chatter">' + + '<field name="message_follower_ids" widget="mail_followers"/>' + + '<field name="message_ids" widget="mail_thread" options="{\'display_log_button\': True}"/>' + + '</div>' + + '</form>', + res_id: 2, + mockRPC: function (route, args) { + if (route === '/mail/read_followers') { + return $.when({ + followers: [{ + id: 10, + name: 'FollowerUser1', + email: 'follower-user1@example.com', + res_model: 'res.partner', + res_id: 1, + }, { + id: 20, + name: 'FollowerUser2', + email: 'follower-user2@example.com', + res_model: 'res.partner', + res_id: 2, + }], + subtypes: [], + }); + } + if (args.method === 'message_get_suggested_recipients') { + return $.when({2: []}); + } + if (args.method === 'get_mention_suggestions') { + throw new Error('should not fetch partners for mentions'); + } + return this._super(route, args); + }, + session: {}, + }); + + assert.strictEqual(form.$('.o_followers_count').text(), '2', + "should have two followers of this document"); + assert.strictEqual(form.$('.o_followers_list > .o_partner').text().replace(/\s+/g, ''), + 'FollowerUser1FollowerUser2', + "should have correct follower names"); + assert.strictEqual(form.$('.o_composer_mention_dropdown').length, 0, + "should not show the mention suggestion dropdown"); + + form.$('.o_chatter_button_new_message').click(); + var $input = form.$('.oe_chatter .o_composer_text_field:first()'); + $input.val('@'); + // the cursor position must be set for the mention manager to detect that we are mentionning + $input[0].selectionStart = 1; + $input[0].selectionEnd = 1; + $input.trigger('keyup'); + + assert.strictEqual(form.$('.o_composer_mention_dropdown').length, 1, + "should show the mention suggestion dropdown"); + + assert.strictEqual(form.$('.o_mention_proposition').length, 4, + "should show 4 mention suggestions"); + assert.strictEqual(form.$('.o_mention_proposition').eq(0).text().replace(/\s+/g, ''), + "FollowerUser1(follower-user1@example.com)", + "should display correct 1st mention suggestion"); + assert.strictEqual(form.$('.o_mention_proposition').eq(1).text().replace(/\s+/g, ''), + "FollowerUser2(follower-user2@example.com)", + "should display correct 2nd mention suggestion"); + assert.ok(form.$('.o_mention_proposition').eq(1).next().hasClass('dropdown-divider'), + "should have a mention separator after last follower mention suggestion"); + assert.strictEqual(form.$('.o_mention_proposition').eq(2).text().replace(/\s+/g, ''), + "NonFollowerUser1(non-follower-user1@example.com)", + "should display correct 3rd mention suggestion"); + assert.strictEqual(form.$('.o_mention_proposition').eq(3).text().replace(/\s+/g, ''), + "NonFollowerUser2(non-follower-user2@example.com)", + "should display correct 4th mention suggestion"); + + //cleanup + form.destroy(); +}); + QUnit.module('FieldMany2ManyTagsEmail', { beforeEach: function () { this.data = { diff --git a/addons/mail/static/tests/discuss_moderation_tests.js b/addons/mail/static/tests/discuss_moderation_tests.js index 51fb7b55c61..4d8e48b4dcb 100644 --- a/addons/mail/static/tests/discuss_moderation_tests.js +++ b/addons/mail/static/tests/discuss_moderation_tests.js @@ -1,6 +1,7 @@ odoo.define('mail.discuss_moderation_tests', function (require) { "use strict"; +var Thread = require('mail.model.Thread'); var mailTestUtils = require('mail.testUtils'); var createDiscuss = mailTestUtils.createDiscuss; @@ -760,5 +761,84 @@ QUnit.test('author: sent message rejected in moderated channel', function (asser }); }); +QUnit.test('no crash when load-more fetching "accepted" message twice', function (assert) { + // This tests requires discuss not loading more messages due to having less + // messages to fetch than available height. This justifies we simply do not + // patch FETCH_LIMIT to 1, as it would detect that more messages could fit + // the empty space (it behaviour is linked to "auto load more"). + var done = assert.async(); + assert.expect(2); + + var FETCH_LIMIT = Thread.prototype._FETCH_LIMIT; + // FETCH LIMIT + 30 should be enough to cover the whole available space in + // the thread of discuss app. + var messageData = []; + _.each(_.range(1, FETCH_LIMIT+31), function (num) { + messageData.push({ + id: num, + body: "<p>test" + num + "</p>", + author_id: [100, "Someone"], + channel_ids: [1], + model: 'mail.channel', + res_id: 1, + moderation_status: 'accepted', + } + ); + }); + + this.data['mail.message'].records = messageData; + + this.data.initMessaging = { + channel_slots: { + channel_channel: [{ + id: 1, + channel_type: "channel", + name: "general", + }], + }, + }; + var count = 0; + + createDiscuss({ + id: 1, + context: {}, + params: {}, + data: this.data, + services: this.services, + session: { partner_id: 3 }, + mockRPC: function (route, args) { + if (args.method === 'message_fetch') { + count++; + if (count === 1) { + // inbox message_fetch + return $.when([]); + } + // general message_fetch + return $.when(messageData); + } + return this._super.apply(this, arguments); + }, + }) + .then(function (discuss) { + var $general = discuss.$('.o_mail_discuss_sidebar') + .find('.o_mail_discuss_item[data-thread-id=1]'); + assert.strictEqual($general.length, 1, + "should have the channel item with id 1"); + assert.strictEqual($general.attr('title'), 'general', + "should have the title 'general'"); + + // click on general + $general.click(); + + // simulate search + discuss.trigger_up('search', { + domains: [['author_id', '=', 100]], + }); + + discuss.destroy(); + done(); + }); +}); + }); }); 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 02c7ec86e6b..1b608f5c37b 100644 --- a/addons/mail/static/tests/systray/systray_messaging_menu_tests.js +++ b/addons/mail/static/tests/systray/systray_messaging_menu_tests.js @@ -146,8 +146,8 @@ QUnit.test('messaging menu widget: messaging menu with 1 record', function (asse messagingMenu.destroy(); }); -QUnit.test('messaging menu widget: no crash when clicking on inbox notification not associated to a document', function (assert) { - assert.expect(3); +QUnit.test('messaging menu widget: open inbox for needaction not linked to any document', function (assert) { + assert.expect(4); var messagingMenu = new MessagingMenu(); testUtils.addMockEnvironment(messagingMenu, { @@ -156,17 +156,6 @@ QUnit.test('messaging menu widget: no crash when clicking on inbox notification session: { partner_id: 1, }, - intercepts: { - /** - * Simulate action 'mail.action_discuss' successfully performed. - * - * @param {OdooEvent} ev - * @param {function} ev.data.on_success called when success action performed - */ - do_action: function (ev) { - ev.data.on_success(); - }, - }, }); messagingMenu.appendTo($('#qunit-fixture')); @@ -195,12 +184,18 @@ QUnit.test('messaging menu widget: no crash when clicking on inbox notification assert.strictEqual($firstChannelPreview.data('preview-id'), 'mailbox_inbox', "should be a preview from channel inbox"); - try { - $firstChannelPreview.click(); - assert.ok(true, "should not have crashed when clicking on needaction preview message"); - } finally { - messagingMenu.destroy(); - } + + testUtils.intercept(messagingMenu, 'do_action', function (ev) { + if (ev.data.action === 'mail.action_discuss') { + assert.step('do_action:' + ev.data.action + ':' + ev.data.options.active_id); + } + }, true); + $firstChannelPreview.click(); + assert.verifySteps( + ['do_action:mail.action_discuss:mailbox_inbox'], + "should open Discuss with Inbox"); + + messagingMenu.destroy(); }); QUnit.test("messaging menu widget: mark as read on thread preview", function ( assert ) { @@ -432,5 +427,164 @@ QUnit.test('update messaging preview on receiving a new message in channel previ messagingMenu.destroy(); }); +QUnit.test('preview of inbox message not linked to document + mark as read', function (assert) { + assert.expect(17); + + this.data.initMessaging = { + needaction_inbox_counter: 2, + }; + + var needactionMessages = [{ + author_id: [1, "Demo"], + body: "<p>*Message1*</p>", + id: 689, + needaction: true, + needaction_partner_ids: [44], + }, { + author_id: [1, "Demo"], + body: "<p>*Message2*</p>", + id: 690, + needaction: true, + needaction_partner_ids: [44], + }]; + this.data['mail.message'].records = + this.data['mail.message'].records.concat(needactionMessages); + + var messagingMenu = new MessagingMenu(); + testUtils.addMockEnvironment(messagingMenu, { + services: this.services, + data: this.data, + session: { + partner_id: 44, + }, + mockRPC: function (route, args) { + if (args.method === 'set_message_done') { + assert.step({ + method: 'set_message_done', + messageIDs: args.args[0], + }); + } + return this._super.apply(this, arguments); + }, + }); + messagingMenu.appendTo($('#qunit-fixture')); + assert.strictEqual(messagingMenu.$('.o_notification_counter').text(), '2', + "should display a counter of 2 on the messaging menu icon"); + + messagingMenu.$('.dropdown-toggle').click(); + + assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 2, + "should display two previews"); + + var $preview1 = messagingMenu.$('.o_mail_preview').eq(0); + var $preview2 = messagingMenu.$('.o_mail_preview').eq(1); + + assert.strictEqual($preview1.data('preview-id'), + "mailbox_inbox", + "1st preview should be from the mailbox inbox"); + assert.strictEqual($preview2.data('preview-id'), + "mailbox_inbox", + "2nd preview should also be from the mailbox inbox"); + assert.ok($preview1.hasClass('o_preview_unread'), + "1st preview should be marked as unread"); + assert.ok($preview2.hasClass('o_preview_unread'), + "2nd preview should also be marked as unread"); + assert.strictEqual($preview1.find('.o_last_message_preview').text().replace(/\s/g, ''), + "Demo:*Message1*", "should correctly display the 1st preview"); + assert.strictEqual($preview2.find('.o_last_message_preview').text().replace(/\s/g, ''), + "Demo:*Message2*", "should correctly display the 2nd preview"); + + $preview1.find('.o_mail_preview_mark_as_read').click(); + assert.verifySteps([{ + method: 'set_message_done', + messageIDs: [689], + }], "should mark 1st preview as read"); + assert.strictEqual(messagingMenu.$('.o_notification_counter').text(), '1', + "should display a counter of 1 on the messaging menu icon after marking one preview as read"); + assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 1, + "should display a single preview remaining"); + assert.strictEqual(messagingMenu.$('.o_mail_preview .o_last_message_preview').text().replace(/\s/g, ''), + "Demo:*Message2*", "preview 2 should be the remaining one"); + + $preview2 = messagingMenu.$('.o_mail_preview'); + $preview2.find('.o_mail_preview_mark_as_read').click(); + assert.verifySteps([{ + method: 'set_message_done', + messageIDs: [689], + }, { + method: 'set_message_done', + messageIDs: [690], + }], "should mark 2nd preview as read"); + assert.strictEqual(messagingMenu.$('.o_notification_counter').text(), '0', + "should display a counter of 0 on the messaging menu icon after marking both previews as read"); + assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 0, + "should display no preview remaining"); + + messagingMenu.destroy(); +}); + +QUnit.test('grouped preview for needaction messages linked to same document', function (assert) { + assert.expect(5); + + // simulate two (read) needaction (mention) messages in channel 'general' + var needactionMessage1 = { + author_id: [1, "Demo"], + body: "<p>@Administrator: ping</p>", + channel_ids: [1], + id: 3, + model: 'mail.channel', + needaction: true, + needaction_partner_ids: [44], + record_name: 'general', + res_id: 1, + }; + var needactionMessage2 = { + author_id: [2, "Other"], + body: "<p>@Administrator: pong</p>", + channel_ids: [1], + id: 4, + model: 'mail.channel', + needaction: true, + needaction_partner_ids: [44], + record_name: 'general', + res_id: 1, + }; + this.data['mail.message'].records = [needactionMessage1, needactionMessage2]; + this.data.initMessaging.channel_slots.channel_channel[0].message_unread_counter = 0; + this.data.initMessaging.needaction_inbox_counter = 2; + + var messagingMenu = new MessagingMenu(); + testUtils.addMockEnvironment(messagingMenu, { + services: this.services, + data: this.data, + session: { + partner_id: 44, + }, + }); + messagingMenu.appendTo($('#qunit-fixture')); + + messagingMenu.$('.dropdown-toggle').click(); + var $previews = messagingMenu.$('.o_mail_preview'); + + assert.strictEqual($previews.length, 2, + "should display two previews (one for needaction, one for channel)"); + + var $needactionPreview = $previews.eq(0); + var $channelPreview = $previews.eq(1); + + assert.strictEqual($needactionPreview.find('.o_preview_counter').text().trim(), "(2)", + "should show two needaction messages in the needaction preview"); + assert.strictEqual($needactionPreview.find('.o_last_message_preview').text().replace(/\s/g, ""), + "Other:@Administrator:pong", + "should display last needaction message on needaction preview"); + assert.strictEqual($channelPreview.find('.o_preview_counter').text().trim(), "", + "should show no unread messages in the channel preview"); + assert.strictEqual($channelPreview.find('.o_last_message_preview').text().replace(/\s/g, ""), + "Other:@Administrator:pong", + "should display last needaction message on channel preview"); + + messagingMenu.destroy(); +}); + }); }); diff --git a/addons/mail/static/tests/thread_window/basic_thread_window_tests.js b/addons/mail/static/tests/thread_window/basic_thread_window_tests.js index f05fd367697..4b8935e81cf 100644 --- a/addons/mail/static/tests/thread_window/basic_thread_window_tests.js +++ b/addons/mail/static/tests/thread_window/basic_thread_window_tests.js @@ -353,6 +353,81 @@ QUnit.test('do not mark as read the newly open thread window from received messa parent.destroy(); }); +QUnit.test('show document link of message linked to a document', function (assert) { + assert.expect(6); + + this.data['mail.channel'] = { + fields: { + name: { + string: "Name", + type: "char", + required: true, + }, + channel_type: { + string: "Channel Type", + type: "selection", + }, + channel_message_ids: { + string: "Messages", + type: "many2many", + relation: 'mail.message' + }, + message_unread_counter: { + string: "Amount of Unread Messages", + type: "integer" + }, + }, + records: [{ + id: 2, + name: "R&D Tasks", + channel_type: "channel", + }], + }; + this.data['mail.message'].records.push({ + author_id: [5, "Someone else"], + body: "<p>Test message</p>", + id: 40, + model: 'some.document', + record_name: 'Some Document', + res_id: 10, + channel_ids: [2], + }); + + this.data.initMessaging.channel_slots.channel_channel.push({ + id: 2, + name: "R&D Tasks", + channel_type: "public", + }); + + var parent = this.createParent({ + data: this.data, + services: this.services, + session: { partner_id: 3 }, + }); + + assert.strictEqual($('.o_thread_window').length, 0, + "no thread window should be open initially"); + + // get channel instance to link to thread window + var channel = parent.call('mail_service', 'getChannel', 2); + channel.detach(); + + var $threadWindow = $('.o_thread_window'); + assert.strictEqual($threadWindow.length, 1, + "a thread window should be open"); + assert.strictEqual($threadWindow.find('.o_thread_window_title').text().trim(), + "#R&D Tasks", + "should be thread window of correct channel"); + assert.strictEqual($threadWindow.find('.o_thread_message').length, 1, + "should contain a single message in thread window"); + assert.ok($threadWindow.find('.o_mail_info').text().replace(/\s/g, "").indexOf('Someoneelse') !== -1, + "message should be from 'Someone else' user"); + assert.ok($threadWindow.find('.o_mail_info').text().replace(/\s/g, "").indexOf('onSomeDocument') !== -1, + "message should link to 'Some Document'"); + + parent.destroy(); +}); + }); }); }); |
