[REF] mail: adapt code after jQuery update
Part of task 1896658 Co-authored-by: Aaron Bohy <aab@odoo.com> Co-authored-by: Christophe Matthieu <chm@odoo.com> Co-authored-by: Mathieu Duckerts-Antoine <dam@odoo.com> Co-authored-by: David Monjoie <dmo@odoo.com> Co-authored-by: Martin Geubelle <mge@odoo.com> Co-authored-by: svs-odoo <svs@odoo.com> Co-authored-by: Vincent Schippefilt <vsc@odoo.com>
This commit is contained in:
committed by
Aaron Bohy
co-authored by
Aaron Bohy
Christophe Matthieu
Mathieu Duckerts-Antoine
David Monjoie
Martin Geubelle
svs-odoo
parent
aa900d976f
commit
1ae64793fa
@@ -25,11 +25,11 @@ var _t = core._t;
|
||||
*
|
||||
* @param {Widget} self a widget instance that can perform RPCs
|
||||
* @param {Array} ids the ids of activities to read
|
||||
* @return {Deferred<Array>} resolved with the activities
|
||||
* @return {Promise<Array>} resolved with the activities
|
||||
*/
|
||||
function _readActivities(self, ids) {
|
||||
if (!ids.length) {
|
||||
return $.when([]);
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
var context = self.getSession().user_context;
|
||||
if (self.record && !_.isEmpty(self.record.getContext())) {
|
||||
@@ -64,7 +64,7 @@ BasicModel.include({
|
||||
* @private
|
||||
* @param {Object} record - an element from the localData
|
||||
* @param {string} fieldName
|
||||
* @return {Deferred<Array>} resolved with the activities
|
||||
* @return {Promise<Array>} resolved with the activities
|
||||
*/
|
||||
_fetchSpecialActivity: function (record, fieldName) {
|
||||
var localID = (record._changes && fieldName in record._changes) ?
|
||||
@@ -144,7 +144,7 @@ var BasicActivity = AbstractField.extend({
|
||||
|
||||
/**
|
||||
* @param {integer} previousActivityTypeID
|
||||
* @return {$.Promise}
|
||||
* @return {Promise}
|
||||
*/
|
||||
scheduleActivity: function () {
|
||||
var callback = this._reload.bind(this, { activity: true, thread: true });
|
||||
@@ -213,7 +213,7 @@ var BasicActivity = AbstractField.extend({
|
||||
* @param {integer} id
|
||||
* @param {integer} previousActivityTypeID
|
||||
* @param {function} callback
|
||||
* @return {$.Deferred}
|
||||
* @return {Promise}
|
||||
*/
|
||||
_openActivityForm: function (id, callback) {
|
||||
var action = {
|
||||
@@ -237,7 +237,7 @@ var BasicActivity = AbstractField.extend({
|
||||
* @param {integer} activityID
|
||||
* @param {string} feedback
|
||||
* @param {integer[]} attachmentIds
|
||||
* @return {$.Promise}
|
||||
* @return {Promise}
|
||||
*/
|
||||
_sendActivityFeedback: function (activityID, feedback, attachmentIds) {
|
||||
return this._rpc({
|
||||
@@ -303,7 +303,7 @@ var BasicActivity = AbstractField.extend({
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
* @returns {$.Promise}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_onEditActivity: function (ev) {
|
||||
ev.preventDefault();
|
||||
@@ -449,7 +449,7 @@ var BasicActivity = AbstractField.extend({
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
* @returns {$.Deferred}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_onPreviewMailTemplate: function (ev) {
|
||||
ev.stopPropagation();
|
||||
@@ -477,7 +477,7 @@ var BasicActivity = AbstractField.extend({
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
* @returns {$.Promise}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_onSendMailTemplate: function (ev) {
|
||||
ev.stopPropagation();
|
||||
@@ -493,7 +493,7 @@ var BasicActivity = AbstractField.extend({
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
* @returns {$.Deferred}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_onScheduleActivity: function (ev) {
|
||||
ev.preventDefault();
|
||||
@@ -504,7 +504,7 @@ var BasicActivity = AbstractField.extend({
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
* @param {Object} options
|
||||
* @returns {$.Promise}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_onUnlinkActivity: function (ev, options) {
|
||||
ev.preventDefault();
|
||||
|
||||
@@ -103,7 +103,7 @@ var Chatter = Widget.extend({
|
||||
}));
|
||||
// start and append the widgets
|
||||
var fieldDefs = _.invoke(this.fields, 'appendTo', $('<div>'));
|
||||
var def = this._dp.add($.when.apply($, fieldDefs));
|
||||
var def = this._dp.add(Promise.all(fieldDefs));
|
||||
this._render(def).then(this._updateMentionSuggestions.bind(this));
|
||||
|
||||
return this._super.apply(this, arguments);
|
||||
@@ -153,7 +153,7 @@ var Chatter = Widget.extend({
|
||||
fieldsToReset = this.fields;
|
||||
}
|
||||
var fieldDefs = _.invoke(fieldsToReset, 'reset', record);
|
||||
var def = this._dp.add($.when.apply($, fieldDefs));
|
||||
var def = this._dp.add(Promise.all(fieldDefs));
|
||||
this._render(def).then(function () {
|
||||
self.$el.height('auto');
|
||||
self._updateMentionSuggestions();
|
||||
@@ -203,17 +203,18 @@ var Chatter = Widget.extend({
|
||||
* Discard changes on the record.
|
||||
*
|
||||
* @private
|
||||
* @returns {$.Deferred} resolved if successfully discarding changes on
|
||||
* @returns {Promise} resolved if successfully discarding changes on
|
||||
* the record, rejected otherwise
|
||||
*/
|
||||
_discardChanges: function () {
|
||||
var def = $.Deferred();
|
||||
this.trigger_up('discard_changes', {
|
||||
recordID: this.record.id,
|
||||
onSuccess: def.resolve.bind(def),
|
||||
onFailure: def.reject.bind(def),
|
||||
var self = this;
|
||||
return new Promise(function (resolve, reject) {
|
||||
self.trigger_up('discard_changes', {
|
||||
recordID: self.record.id,
|
||||
onSuccess: resolve,
|
||||
onFailure: reject,
|
||||
});
|
||||
});
|
||||
return def;
|
||||
},
|
||||
/**
|
||||
* Discard changes on the record if the message will reload the record
|
||||
@@ -221,14 +222,14 @@ var Chatter = Widget.extend({
|
||||
*
|
||||
* @private
|
||||
* @param {Object} messageData
|
||||
* @return {$.Deferred} resolved if no reload or proceed to discard the
|
||||
* @return {Promise} resolved if no reload or proceed to discard the
|
||||
* changes on the record, rejected otherwise
|
||||
*/
|
||||
_discardOnReload: function (messageData) {
|
||||
if (this._reloadAfterPost(messageData)) {
|
||||
return this._discardChanges();
|
||||
}
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
@@ -323,7 +324,7 @@ var Chatter = Widget.extend({
|
||||
self._reloadAttachmentBox();
|
||||
self.trigger_up('reload', {fieldNames: ['message_attachment_count'], keepChanges: true});
|
||||
}
|
||||
}).fail(function () {
|
||||
}).guardedCatch(function () {
|
||||
self._enableComposer();
|
||||
});
|
||||
});
|
||||
@@ -375,9 +376,9 @@ var Chatter = Widget.extend({
|
||||
_render: function (def) {
|
||||
// the rendering of the chatter is aynchronous: relational data of its fields needs to be
|
||||
// fetched (in some case, it might be synchronous as they hold an internal cache).
|
||||
// this function takes a deferred as argument, which is resolved once all fields have
|
||||
// this function takes a promise as argument, which is resolved once all fields have
|
||||
// fetched their data
|
||||
// this function appends the fields where they should be once the given deferred is resolved
|
||||
// this function appends the fields where they should be once the given promise is resolved
|
||||
// and if it takes more than 500ms, displays a spinner to indicate that it is loading
|
||||
var self = this;
|
||||
|
||||
@@ -385,6 +386,11 @@ var Chatter = Widget.extend({
|
||||
concurrency.rejectAfter(concurrency.delay(500), def).then(function () {
|
||||
$spinner.appendTo(self.$el);
|
||||
});
|
||||
var always = function () {
|
||||
// disable widgets in create mode, otherwise enable
|
||||
self._isCreateMode ? self._disableChatter() : self._enableChatter();
|
||||
$spinner.remove();
|
||||
};
|
||||
|
||||
return def.then(function () {
|
||||
if (self.fields.activity) {
|
||||
@@ -400,11 +406,7 @@ var Chatter = Widget.extend({
|
||||
if (self.fields.thread) {
|
||||
self.fields.thread.$el.appendTo(self.$el);
|
||||
}
|
||||
}).always(function () {
|
||||
// disable widgets in create mode, otherwise enable
|
||||
self._isCreateMode ? self._disableChatter() : self._enableChatter();
|
||||
$spinner.remove();
|
||||
});
|
||||
}).then(always).guardedCatch(always);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
@@ -517,7 +519,7 @@ var Chatter = Widget.extend({
|
||||
if (!this._areAttachmentsLoaded) {
|
||||
def = this._fetchAttachments();
|
||||
}
|
||||
$.when(def).then(this._openAttachmentBox.bind(this));
|
||||
Promise.resolve(def).then(this._openAttachmentBox.bind(this));
|
||||
}
|
||||
},
|
||||
/**
|
||||
@@ -534,10 +536,10 @@ var Chatter = Widget.extend({
|
||||
_onOpenComposerMessage: function () {
|
||||
var self = this;
|
||||
if (!this.suggested_partners_def) {
|
||||
this.suggested_partners_def = $.Deferred();
|
||||
var method = 'message_get_suggested_recipients';
|
||||
var args = [[this.context.default_res_id], this.context];
|
||||
this._rpc({model: this.record.model, method: method, args: args})
|
||||
this.suggested_partners_def = new Promise(function (resolve, reject) {
|
||||
var method = 'message_get_suggested_recipients';
|
||||
var args = [[self.context.default_res_id], self.context];
|
||||
self._rpc({model: self.record.model, method: method, args: args})
|
||||
.then(function (result) {
|
||||
if (!self.suggested_partners_def) {
|
||||
return; // widget has been reset (e.g. we just switched to another record)
|
||||
@@ -555,8 +557,9 @@ var Chatter = Widget.extend({
|
||||
reason: recipient[2],
|
||||
});
|
||||
});
|
||||
self.suggested_partners_def.resolve(suggested_partners);
|
||||
resolve(suggested_partners);
|
||||
});
|
||||
});
|
||||
}
|
||||
this.suggested_partners_def.then(function (suggested_partners) {
|
||||
self._openComposer({ isLog: false, suggested_partners: suggested_partners });
|
||||
|
||||
@@ -128,7 +128,7 @@ var BasicComposer = Widget.extend({
|
||||
.on('update_typing_partners', this, this._onUpdateTypingPartners);
|
||||
|
||||
// Mention
|
||||
this._mentionManager.prependTo(this.$('.o_composer'));
|
||||
var prependPromise = this._mentionManager.prependTo(this.$('.o_composer'));
|
||||
|
||||
// Drag-Drop files
|
||||
// Allowing body to detect dragenter and dragleave for display
|
||||
@@ -137,7 +137,7 @@ var BasicComposer = Widget.extend({
|
||||
$body.on('dragleave.' + this._dropZoneNS, this._onBodyFileDragLeave.bind(this));
|
||||
$body.on("dragover." + this._dropZoneNS, this._onBodyFileDragover.bind(this));
|
||||
$body.on("drop." + this._dropZoneNS, this._onBodyFileDrop.bind(this));
|
||||
return this._super();
|
||||
return Promise.all([this._super(), prependPromise]);
|
||||
},
|
||||
destroy: function () {
|
||||
$("body").off('dragleave.' + this._dropZoneNS);
|
||||
@@ -236,7 +236,7 @@ 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 list of list of
|
||||
* @param {Promise<Object[]>} prefetchedPartners list of list of
|
||||
* prefetched partners.
|
||||
*/
|
||||
mentionSetPrefetchedPartners: function (prefetchedPartners) {
|
||||
@@ -299,20 +299,21 @@ var BasicComposer = Widget.extend({
|
||||
/**
|
||||
* @private
|
||||
* @param {string} search
|
||||
* @returns {$.Deferred<Object[]>}
|
||||
* @returns {Promise<Object[]>}
|
||||
*/
|
||||
_mentionGetCannedResponses: function (search) {
|
||||
var self = this;
|
||||
var def = $.Deferred();
|
||||
clearTimeout(this._cannedTimeout);
|
||||
this._cannedTimeout = setTimeout(function () {
|
||||
var cannedResponses = self.call('mail_service', 'getCannedResponses');
|
||||
var matches = fuzzy.filter(utils.unaccent(search), _.pluck(cannedResponses, 'source'));
|
||||
var indexes = _.pluck(matches.slice(0, self.options.mentionFetchLimit), 'index');
|
||||
def.resolve(_.map(indexes, function (index) {
|
||||
return cannedResponses[index];
|
||||
}));
|
||||
}, 500);
|
||||
var def = new Promise(function (resolve, reject) {
|
||||
clearTimeout(self._cannedTimeout);
|
||||
self._cannedTimeout = setTimeout(function () {
|
||||
var cannedResponses = self.call('mail_service', 'getCannedResponses');
|
||||
var matches = fuzzy.filter(utils.unaccent(search), _.pluck(cannedResponses, 'source'));
|
||||
var indexes = _.pluck(matches.slice(0, self.options.mentionFetchLimit), 'index');
|
||||
resolve(_.map(indexes, function (index) {
|
||||
return cannedResponses[index];
|
||||
}));
|
||||
}, 500);
|
||||
});
|
||||
return def;
|
||||
},
|
||||
/**
|
||||
@@ -346,7 +347,7 @@ var BasicComposer = Widget.extend({
|
||||
*/
|
||||
_mentionFetchPartners: function (search) {
|
||||
var self = this;
|
||||
return $.when(this._mentionPrefetchedPartners).then(function (prefetchedPartners) {
|
||||
return Promise.resolve(this._mentionPrefetchedPartners).then(function (prefetchedPartners) {
|
||||
// filter prefetched partners with the given search string
|
||||
var suggestions = [];
|
||||
var limit = self.options.mentionFetchLimit;
|
||||
@@ -371,7 +372,7 @@ var BasicComposer = Widget.extend({
|
||||
{ limit: limit, search: search }
|
||||
);
|
||||
}
|
||||
return $.when(suggestions).then(function (suggestions) {
|
||||
return Promise.resolve(suggestions).then(function (suggestions) {
|
||||
//add im_status on suggestions
|
||||
_.each(suggestions, function (suggestionsSet) {
|
||||
_.each(suggestionsSet, function (suggestion) {
|
||||
@@ -387,27 +388,27 @@ var BasicComposer = Widget.extend({
|
||||
* @param {string} model
|
||||
* @param {string} method
|
||||
* @param {Object} kwargs
|
||||
* @return {$.Deferred}
|
||||
* @return {Promise}
|
||||
*/
|
||||
_mentionFetchThrottled: function (model, method, kwargs) {
|
||||
var self = this;
|
||||
// Delays the execution of the RPC to prevent unnecessary RPCs when the user is still typing
|
||||
var def = $.Deferred();
|
||||
clearTimeout(this.mentionFetchTimer);
|
||||
this.mentionFetchTimer = setTimeout(function () {
|
||||
return self._rpc({model: model, method: method, kwargs: kwargs})
|
||||
return new Promise(function (resolve, reject) {
|
||||
clearTimeout(self.mentionFetchTimer);
|
||||
self.mentionFetchTimer = setTimeout(function () {
|
||||
return self._rpc({model: model, method: method, kwargs: kwargs})
|
||||
.then(function (results) {
|
||||
def.resolve(results);
|
||||
resolve(results);
|
||||
});
|
||||
}, this.MENTION_THROTTLE);
|
||||
return def;
|
||||
}, self.MENTION_THROTTLE);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {$.Deferred}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_preprocessMessage: function () {
|
||||
// Return a deferred as this function is extended with asynchronous
|
||||
// Return a promise as this function is extended with asynchronous
|
||||
// behavior for the chatter composer
|
||||
|
||||
//Removing unwanted extra spaces from message
|
||||
@@ -420,7 +421,7 @@ var BasicComposer = Widget.extend({
|
||||
var commands = this.options.commandsEnabled ?
|
||||
this._mentionManager.getListenerSelection('/') :
|
||||
[];
|
||||
return $.when({
|
||||
return Promise.resolve({
|
||||
content: this._mentionManager.generateLinks(value),
|
||||
attachment_ids: _.pluck(this.get('attachment_ids'), 'id'),
|
||||
partner_ids: _.uniq(_.pluck(this._mentionManager.getListenerSelection('@'), 'id')),
|
||||
|
||||
@@ -59,109 +59,112 @@ var ChatterComposer = BasicComposer.extend({
|
||||
* @private
|
||||
* @param {Array} checkedSuggestedPartners list of 'recipient' partners to
|
||||
* complete informations or validate
|
||||
* @returns {Deferred} resolved with the list of checked suggested partners
|
||||
* @returns {Promise} resolved with the list of checked suggested partners
|
||||
* (real partner)
|
||||
**/
|
||||
_checkSuggestedPartners: function (checkedSuggestedPartners) {
|
||||
var self = this;
|
||||
var checkDone = $.Deferred();
|
||||
|
||||
var recipients = _.filter(checkedSuggestedPartners, function (recipient) {
|
||||
return recipient.checked;
|
||||
});
|
||||
var recipientsToFind = _.filter(recipients, function (recipient) {
|
||||
return (! recipient.partner_id);
|
||||
});
|
||||
var namesToFind = _.pluck(recipientsToFind, 'full_name');
|
||||
var recipientsToCheck = _.filter(recipients, function (recipient) {
|
||||
return (recipient.partner_id && ! recipient.email_address);
|
||||
});
|
||||
var recipientIDs = _.pluck(_.filter(recipients, function (recipient) {
|
||||
return recipient.partner_id && recipient.email_address;
|
||||
}), 'partner_id');
|
||||
|
||||
var namesToRemove = [];
|
||||
var recipientIDsToRemove = [];
|
||||
|
||||
// have unknown names
|
||||
// -> call message_get_partner_info_from_emails to try to find
|
||||
// partner_id
|
||||
var def;
|
||||
if (namesToFind.length > 0) {
|
||||
def = this._rpc({
|
||||
model: this._model,
|
||||
method: 'message_partner_info_from_emails',
|
||||
args: [[this.context.default_res_id], namesToFind],
|
||||
});
|
||||
}
|
||||
|
||||
// for unknown names + incomplete partners
|
||||
// -> open popup - cancel = remove from recipients
|
||||
$.when(def).pipe(function (result) {
|
||||
result = result || [];
|
||||
var emailDefs = [];
|
||||
var recipientPopups = result.concat(recipientsToCheck);
|
||||
|
||||
_.each(recipientPopups, function (partnerInfo) {
|
||||
var deferred = $.Deferred();
|
||||
emailDefs.push(deferred);
|
||||
|
||||
var partnerName = partnerInfo.full_name;
|
||||
var partnerID = partnerInfo.partner_id;
|
||||
var parsedEmail = mailUtils.parseEmail(partnerName);
|
||||
|
||||
var dialog = new viewDialogs.FormViewDialog(self, {
|
||||
res_model: 'res.partner',
|
||||
res_id: partnerID,
|
||||
context: {
|
||||
active_model: self._model,
|
||||
active_id: self.context.default_res_id,
|
||||
force_email: true,
|
||||
ref: 'compound_context',
|
||||
default_name: parsedEmail[0],
|
||||
default_email: parsedEmail[1],
|
||||
},
|
||||
title: _t("Please complete customer's informations"),
|
||||
disable_multiple_selection: true,
|
||||
}).open();
|
||||
dialog.on('closed', self, function () {
|
||||
deferred.resolve();
|
||||
});
|
||||
dialog.opened().then(function () {
|
||||
dialog.form_view.on('on_button_cancel', self, function () {
|
||||
namesToRemove.push(partnerName);
|
||||
if (partnerID) {
|
||||
recipientIDsToRemove.push(partnerID);
|
||||
}
|
||||
});
|
||||
});
|
||||
var checkDone = new Promise(function (resolve, reject) {
|
||||
var recipients = _.filter(checkedSuggestedPartners, function (recipient) {
|
||||
return recipient.checked;
|
||||
});
|
||||
$.when.apply($, emailDefs).then(function () {
|
||||
var newNamesToFind = _.difference(namesToFind, namesToRemove);
|
||||
var def;
|
||||
if (newNamesToFind.length > 0) {
|
||||
def = self._rpc({
|
||||
model: self._model,
|
||||
method: 'message_partner_info_from_emails',
|
||||
args: [[self.context.default_res_id], newNamesToFind, true],
|
||||
var recipientsToFind = _.filter(recipients, function (recipient) {
|
||||
return (! recipient.partner_id);
|
||||
});
|
||||
var namesToFind = _.pluck(recipientsToFind, 'full_name');
|
||||
var recipientsToCheck = _.filter(recipients, function (recipient) {
|
||||
return (recipient.partner_id && ! recipient.email_address);
|
||||
});
|
||||
var recipientIDs = _.pluck(_.filter(recipients, function (recipient) {
|
||||
return recipient.partner_id && recipient.email_address;
|
||||
}), 'partner_id');
|
||||
|
||||
var namesToRemove = [];
|
||||
var recipientIDsToRemove = [];
|
||||
|
||||
// have unknown names
|
||||
// -> call message_get_partner_info_from_emails to try to find
|
||||
// partner_id
|
||||
var def;
|
||||
if (namesToFind.length > 0) {
|
||||
def = self._rpc({
|
||||
model: self._model,
|
||||
method: 'message_partner_info_from_emails',
|
||||
args: [[self.context.default_res_id], namesToFind],
|
||||
});
|
||||
}
|
||||
|
||||
// for unknown names + incomplete partners
|
||||
// -> open popup - cancel = remove from recipients
|
||||
Promise.resolve(def).then(function (result) {
|
||||
result = result || [];
|
||||
var emailDefs = [];
|
||||
var recipientPopups = result.concat(recipientsToCheck);
|
||||
|
||||
_.each(recipientPopups, function (partnerInfo) {
|
||||
var prom = new Promise(function(innerResolve, innerReject) {
|
||||
var partnerName = partnerInfo.full_name;
|
||||
var partnerID = partnerInfo.partner_id;
|
||||
var parsedEmail = mailUtils.parseEmail(partnerName);
|
||||
|
||||
var dialog = new viewDialogs.FormViewDialog(self, {
|
||||
res_model: 'res.partner',
|
||||
res_id: partnerID,
|
||||
context: {
|
||||
active_model: self._model,
|
||||
active_id: self.context.default_res_id,
|
||||
force_email: true,
|
||||
ref: 'compound_context',
|
||||
default_name: parsedEmail[0],
|
||||
default_email: parsedEmail[1],
|
||||
},
|
||||
title: _t("Please complete customer's informations"),
|
||||
disable_multiple_selection: true,
|
||||
}).open();
|
||||
dialog.on('closed', self, function () {
|
||||
innerResolve();
|
||||
});
|
||||
dialog.opened().then(function () {
|
||||
dialog.form_view.on('on_button_cancel', self, function () {
|
||||
namesToRemove.push(partnerName);
|
||||
if (partnerID) {
|
||||
recipientIDsToRemove.push(partnerID);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
$.when(def).pipe(function (result) {
|
||||
result = result || [];
|
||||
var recipientPopups = result.concat(recipientsToCheck);
|
||||
_.each(recipientPopups, function (partnerInfo) {
|
||||
if (
|
||||
partnerInfo.partner_id &&
|
||||
_.indexOf(partnerInfo.partner_id, recipientIDsToRemove) === -1
|
||||
) {
|
||||
recipientIDs.push(partnerInfo.partner_id);
|
||||
}
|
||||
});
|
||||
}).pipe(function () {
|
||||
checkDone.resolve(recipientIDs);
|
||||
|
||||
emailDefs.push(prom);
|
||||
|
||||
});
|
||||
Promise.all(emailDefs).then(function () {
|
||||
var newNamesToFind = _.difference(namesToFind, namesToRemove);
|
||||
var def;
|
||||
if (newNamesToFind.length > 0) {
|
||||
def = self._rpc({
|
||||
model: self._model,
|
||||
method: 'message_partner_info_from_emails',
|
||||
args: [[self.context.default_res_id], newNamesToFind, true],
|
||||
});
|
||||
}
|
||||
Promise.resolve(def).then(function (result) {
|
||||
result = result || [];
|
||||
var recipientPopups = result.concat(recipientsToCheck);
|
||||
_.each(recipientPopups, function (partnerInfo) {
|
||||
if (
|
||||
partnerInfo.partner_id &&
|
||||
_.indexOf(partnerInfo.partner_id, recipientIDsToRemove) === -1
|
||||
) {
|
||||
recipientIDs.push(partnerInfo.partner_id);
|
||||
}
|
||||
});
|
||||
}).then(function () {
|
||||
resolve(recipientIDs);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return checkDone;
|
||||
},
|
||||
/**
|
||||
@@ -187,41 +190,40 @@ var ChatterComposer = BasicComposer.extend({
|
||||
/**
|
||||
* @override
|
||||
* @private
|
||||
* @returns {$.Deferred}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_preprocessMessage: function () {
|
||||
var self = this;
|
||||
var def = $.Deferred();
|
||||
this._super().then(function (message) {
|
||||
message = _.extend(message, {
|
||||
subtype: 'mail.mt_comment',
|
||||
message_type: 'comment',
|
||||
context: _.defaults({}, self.context, session.user_context),
|
||||
});
|
||||
|
||||
// Subtype
|
||||
if (self.options.isLog) {
|
||||
message.subtype = 'mail.mt_note';
|
||||
}
|
||||
|
||||
// Partner_ids
|
||||
if (!self.options.isLog) {
|
||||
var checkedSuggestedPartners = self._getCheckedSuggestedPartners();
|
||||
self._checkSuggestedPartners(checkedSuggestedPartners).done(function (partnerIDs) {
|
||||
message.partner_ids = (message.partner_ids || []).concat(partnerIDs);
|
||||
// update context
|
||||
message.context = _.defaults({}, message.context, {
|
||||
mail_post_autofollow: true,
|
||||
});
|
||||
def.resolve(message);
|
||||
return new Promise(function (resolve, reject) {
|
||||
self._super().then(function (message) {
|
||||
message = _.extend(message, {
|
||||
subtype: 'mail.mt_comment',
|
||||
message_type: 'comment',
|
||||
context: _.defaults({}, self.context, session.user_context),
|
||||
});
|
||||
} else {
|
||||
def.resolve(message);
|
||||
}
|
||||
|
||||
// Subtype
|
||||
if (self.options.isLog) {
|
||||
message.subtype = 'mail.mt_note';
|
||||
}
|
||||
|
||||
// Partner_ids
|
||||
if (!self.options.isLog) {
|
||||
var checkedSuggestedPartners = self._getCheckedSuggestedPartners();
|
||||
self._checkSuggestedPartners(checkedSuggestedPartners).then(function (partnerIDs) {
|
||||
message.partner_ids = (message.partner_ids || []).concat(partnerIDs);
|
||||
// update context
|
||||
message.context = _.defaults({}, message.context, {
|
||||
mail_post_autofollow: true,
|
||||
});
|
||||
resolve(message);
|
||||
});
|
||||
} else {
|
||||
resolve(message);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
return def;
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
@@ -244,20 +246,20 @@ var ChatterComposer = BasicComposer.extend({
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var recipientDoneDef = $.Deferred();
|
||||
|
||||
// any operation on the full-composer will reload the record, so
|
||||
// warn the user that any unsaved changes on the record will be lost.
|
||||
this.trigger_up('discard_record_changes', {
|
||||
proceed: function () {
|
||||
if (self.options.isLog) {
|
||||
recipientDoneDef.resolve([]);
|
||||
} else {
|
||||
var checkedSuggestedPartners = self._getCheckedSuggestedPartners();
|
||||
self._checkSuggestedPartners(checkedSuggestedPartners)
|
||||
.then(recipientDoneDef.resolve.bind(recipientDoneDef));
|
||||
}
|
||||
},
|
||||
var recipientDoneDef = new Promise(function (resolve, reject) {
|
||||
// any operation on the full-composer will reload the record, so
|
||||
// warn the user that any unsaved changes on the record will be lost.
|
||||
self.trigger_up('discard_record_changes', {
|
||||
proceed: function () {
|
||||
if (self.options.isLog) {
|
||||
resolve([]);
|
||||
} else {
|
||||
var checkedSuggestedPartners = self._getCheckedSuggestedPartners();
|
||||
self._checkSuggestedPartners(checkedSuggestedPartners)
|
||||
.then(resolve);
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
recipientDoneDef.then(function (partnerIDs) {
|
||||
|
||||
@@ -102,7 +102,7 @@ var ExtendedComposer = BasicComposer.extend({
|
||||
/**
|
||||
* @override
|
||||
* @private
|
||||
* @returns {$.Deferred}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_preprocessMessage: function () {
|
||||
var self = this;
|
||||
|
||||
@@ -114,7 +114,7 @@ var MentionManager = Widget.extend({
|
||||
|
||||
if (this._activeListener) {
|
||||
var mentionWord = this._mentionWord;
|
||||
$.when(this._activeListener.fetchCallback(mentionWord))
|
||||
Promise.resolve(this._activeListener.fetchCallback(mentionWord))
|
||||
.then(function (suggestions) {
|
||||
if (mentionWord === self._mentionWord) {
|
||||
// update suggestions only if mentionWord didn't change
|
||||
|
||||
@@ -82,7 +82,7 @@ var PartnerInviteDialog = Dialog.extend({
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @returns {$.Promise}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_addChannel: function () {
|
||||
var self = this;
|
||||
@@ -297,7 +297,7 @@ var Discuss = AbstractAction.extend({
|
||||
* @override
|
||||
*/
|
||||
willStart: function () {
|
||||
return $.when(this._super(), this.call('mail_service', 'isReady'));
|
||||
return Promise.all([this._super(), this.call('mail_service', 'isReady')]);
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
@@ -331,7 +331,7 @@ var Discuss = AbstractAction.extend({
|
||||
this._extendedComposer.appendTo(this.$('.o_mail_discuss_content')));
|
||||
defs.push(this._super.apply(this, arguments));
|
||||
|
||||
return $.when.apply($, defs)
|
||||
return Promise.all(defs)
|
||||
.then(function () {
|
||||
return self._setThread(self._defaultThreadID);
|
||||
})
|
||||
@@ -474,7 +474,7 @@ var Discuss = AbstractAction.extend({
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {$.Promise}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_fetchAndRenderThread: function () {
|
||||
var self = this;
|
||||
@@ -567,7 +567,7 @@ var Discuss = AbstractAction.extend({
|
||||
* loaded when scrolling to the top, so they can't be loaded if there is no
|
||||
* scrollbar)
|
||||
*
|
||||
* @returns {Deferred} resolved when there are enough messages to fill the
|
||||
* @returns {Promise} resolved when there are enough messages to fill the
|
||||
* screen, or when there is no more message to fetch
|
||||
*/
|
||||
_loadEnoughMessages: function () {
|
||||
@@ -583,7 +583,7 @@ var Discuss = AbstractAction.extend({
|
||||
* Load more messages for the current thread
|
||||
*
|
||||
* @private
|
||||
* @returns {$.Promise}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_loadMoreMessages: function () {
|
||||
var self = this;
|
||||
@@ -647,7 +647,7 @@ var Discuss = AbstractAction.extend({
|
||||
autoFocus: true,
|
||||
source: function (request, response) {
|
||||
self._lastSearchVal = _.escape(request.term);
|
||||
self._searchChannel(self._lastSearchVal).done(function (result){
|
||||
self._searchChannel(self._lastSearchVal).then(function (result){
|
||||
result.push({
|
||||
label: _.str.sprintf(
|
||||
'<strong>' + _t("Create %s (Public)") + '</strong>',
|
||||
@@ -689,7 +689,7 @@ var Discuss = AbstractAction.extend({
|
||||
autoFocus: true,
|
||||
source: function (request, response) {
|
||||
self._lastSearchVal = _.escape(request.term);
|
||||
self.call('mail_service', 'searchPartner', self._lastSearchVal, 10).done(response);
|
||||
self.call('mail_service', 'searchPartner', self._lastSearchVal, 10).then(response);
|
||||
},
|
||||
select: function (ev, ui) {
|
||||
var partnerID = ui.item.id;
|
||||
@@ -819,7 +819,7 @@ var Discuss = AbstractAction.extend({
|
||||
* Renders, binds events and appends a thread widget.
|
||||
*
|
||||
* @private
|
||||
* @returns {Deferred}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_renderThread: function () {
|
||||
this._threadWidget = new ThreadWidget(this, {
|
||||
@@ -877,7 +877,7 @@ var Discuss = AbstractAction.extend({
|
||||
/**
|
||||
* @private
|
||||
* @param {string} searchVal
|
||||
* @returns {$.Promise<Array>}
|
||||
* @returns {Promise<Array>}
|
||||
*/
|
||||
_searchChannel: function (searchVal){
|
||||
return this._rpc({
|
||||
@@ -915,7 +915,7 @@ var Discuss = AbstractAction.extend({
|
||||
this._extendedComposer.do_show();
|
||||
|
||||
this._threadWidget.scrollToMessage({
|
||||
msgID: messageID,
|
||||
messageID: messageID,
|
||||
duration: 200,
|
||||
onlyIfNecessary: true
|
||||
});
|
||||
@@ -927,7 +927,7 @@ var Discuss = AbstractAction.extend({
|
||||
*
|
||||
* @private
|
||||
* @param {integer} threadID a thread with such ID
|
||||
* @returns {$.Promise}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_setThread: function (threadID) {
|
||||
var self = this;
|
||||
@@ -1483,9 +1483,6 @@ var Discuss = AbstractAction.extend({
|
||||
} else {
|
||||
self._threadWidget.scrollToBottom();
|
||||
}
|
||||
})
|
||||
.fail(function () {
|
||||
// todo: display notifications
|
||||
});
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -116,7 +116,7 @@ Discuss.include({
|
||||
this._thread = thread;
|
||||
if (thread.getType() !== 'mailbox') {
|
||||
this.call('mail_service', 'openThreadWindow', threadID);
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
return this._super.apply(this, arguments);
|
||||
}
|
||||
@@ -179,7 +179,7 @@ Discuss.include({
|
||||
});
|
||||
def = this.call('mail_service', 'getChannelPreviews', channels);
|
||||
}
|
||||
return $.when(def).then(function (previews) {
|
||||
return Promise.resolve(def).then(function (previews) {
|
||||
// update content
|
||||
if (inMailbox) {
|
||||
if (!previouslyInInbox) {
|
||||
|
||||
@@ -76,7 +76,7 @@ var DocumentViewer = Widget.extend({
|
||||
start: function () {
|
||||
this.$el.modal('show');
|
||||
this.$el.on('hidden.bs.modal', _.bind(this._onDestroy, this));
|
||||
this.$('.o_viewer_img').load(_.bind(this._onImageLoaded, this));
|
||||
this.$('.o_viewer_img').on("load", _.bind(this._onImageLoaded, this));
|
||||
this.$('[data-toggle="tooltip"]').tooltip({delay: 0});
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
@@ -132,7 +132,7 @@ var DocumentViewer = Widget.extend({
|
||||
this.$('.o_viewer_content').html(QWeb.render('DocumentViewer.Content', {
|
||||
widget: this
|
||||
}));
|
||||
this.$('.o_viewer_img').load(_.bind(this._onImageLoaded, this));
|
||||
this.$('.o_viewer_img').on("load", _.bind(this._onImageLoaded, this));
|
||||
this.$('[data-toggle="tooltip"]').tooltip({delay: 0});
|
||||
this._reset();
|
||||
},
|
||||
|
||||
@@ -55,14 +55,14 @@ var Followers = AbstractField.extend({
|
||||
// note: the rendering of this widget is asynchronous as it needs to
|
||||
// fetch the details of the followers, but it performs a first rendering
|
||||
// synchronously (_displayGeneric), and updates its rendering once it
|
||||
// has fetched the required data, so this function doesn't return a deferred
|
||||
// has fetched the required data, so this function doesn't return a promise
|
||||
// as we don't want to wait to the data to be loaded to display the widget
|
||||
var self = this;
|
||||
var fetch_def = this.dp.add(this._readFollowers());
|
||||
|
||||
concurrency.rejectAfter(concurrency.delay(0), fetch_def).then(this._displayGeneric.bind(this));
|
||||
|
||||
fetch_def.then(function () {
|
||||
return fetch_def.then(function () {
|
||||
self._displayButtons();
|
||||
self._displayFollowers(self.followers);
|
||||
if (self.subtypes) { // current user is follower
|
||||
@@ -203,7 +203,7 @@ var Followers = AbstractField.extend({
|
||||
params: { follower_ids: missing_ids, res_model: this.model }
|
||||
});
|
||||
}
|
||||
return $.when(def).then(function (results) {
|
||||
return Promise.resolve(def).then(function (results) {
|
||||
if (results) {
|
||||
self.followers = _.uniq(results.followers.concat(self.followers), 'id');
|
||||
if (results.subtypes) { //read_followers will return False if current user is not in the list
|
||||
@@ -241,27 +241,27 @@ var Followers = AbstractField.extend({
|
||||
*/
|
||||
_unfollow: function (ids) {
|
||||
var self = this;
|
||||
var def = $.Deferred();
|
||||
var text = _t("Warning! \n If you remove a follower, he won't be notified of any email or discussion on this document.\n Do you really want to remove this follower ?");
|
||||
Dialog.confirm(this, text, {
|
||||
confirm_callback: function () {
|
||||
var args = [
|
||||
[self.res_id],
|
||||
ids.partner_ids,
|
||||
ids.channel_ids,
|
||||
{}, // FIXME
|
||||
];
|
||||
self._rpc({
|
||||
return new Promise(function (resolve, reject) {
|
||||
var text = _t("Warning! \n If you remove a follower, he won't be notified of any email or discussion on this document.\n Do you really want to remove this follower ?");
|
||||
Dialog.confirm(this, text, {
|
||||
confirm_callback: function () {
|
||||
var args = [
|
||||
[self.res_id],
|
||||
ids.partner_ids,
|
||||
ids.channel_ids,
|
||||
{}, // FIXME
|
||||
];
|
||||
self._rpc({
|
||||
model: self.model,
|
||||
method: 'message_unsubscribe',
|
||||
args: args
|
||||
})
|
||||
.then(self._reload.bind(self));
|
||||
def.resolve();
|
||||
},
|
||||
cancel_callback: def.reject.bind(def),
|
||||
resolve();
|
||||
},
|
||||
cancel_callback: reject,
|
||||
});
|
||||
});
|
||||
return def;
|
||||
},
|
||||
_updateSubscription: function (event, followerID, isChannel) {
|
||||
var ids = {};
|
||||
@@ -290,7 +290,7 @@ var Followers = AbstractField.extend({
|
||||
|
||||
// If no more subtype followed, unsubscribe the follower
|
||||
if (!checklist.length) {
|
||||
this._unfollow(ids).fail(function () {
|
||||
this._unfollow(ids).guardedCatch(function () {
|
||||
$(event.currentTarget).find('input').addBack('input').prop('checked', true);
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -50,18 +50,24 @@ FormRenderer.include({
|
||||
* @private
|
||||
*/
|
||||
_renderNode: function (node) {
|
||||
var self = this;
|
||||
if (node.tag === 'div' && node.attrs.class === 'oe_chatter') {
|
||||
if (!this.chatter) {
|
||||
this.chatter = new Chatter(this, this.state, this.mailFields, {
|
||||
isEditable: this.activeActions.edit,
|
||||
viewType: 'form',
|
||||
});
|
||||
this.chatter.appendTo($('<div>'));
|
||||
this._handleAttributes(this.chatter.$el, node);
|
||||
|
||||
var $temporaryParentDiv = $('<div>');
|
||||
this.defs.push(this.chatter.appendTo($temporaryParentDiv).then(function () {
|
||||
self.chatter.$el.unwrap();
|
||||
self._handleAttributes(self.chatter.$el, node);
|
||||
}));
|
||||
return $temporaryParentDiv;
|
||||
} else {
|
||||
this.chatter.update(this.state);
|
||||
return this.chatter.$el;
|
||||
}
|
||||
return this.chatter.$el;
|
||||
} else {
|
||||
return this._super.apply(this, arguments);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ BasicModel.include({
|
||||
* @private
|
||||
* @param {Object} record - an element from the localData
|
||||
* @param {string} fieldName
|
||||
* @return {Deferred<Object>} the deferred is resolved with the
|
||||
* @return {Promise<Object>} the promise is resolved with the
|
||||
* invalidPartnerIds
|
||||
*/
|
||||
_setInvalidMany2ManyTagsEmail: function (record, fieldName) {
|
||||
@@ -42,10 +42,10 @@ BasicModel.include({
|
||||
var changes = {operation: 'DELETE', ids: _.pluck(invalidPartnerIds, 'id')};
|
||||
def = this._applyX2ManyChange(record, fieldName, changes);
|
||||
}
|
||||
return $.when(def).then(function () {
|
||||
return $.when({
|
||||
return Promise.resolve(def).then(function () {
|
||||
return {
|
||||
invalidPartnerIds: _.pluck(invalidPartnerIds, 'res_id'),
|
||||
});
|
||||
};
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -65,7 +65,7 @@ var FieldMany2ManyTagsEmail = M2MTags.extend({
|
||||
* Open a popup for each invalid partners (without email) to fill the email.
|
||||
*
|
||||
* @private
|
||||
* @returns {Deferred}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_checkEmailPopup: function () {
|
||||
var self = this;
|
||||
@@ -75,25 +75,25 @@ var FieldMany2ManyTagsEmail = M2MTags.extend({
|
||||
|
||||
// propose the user to correct invalid partners
|
||||
_.each(this.record.specialData[this.name].invalidPartnerIds, function (resID) {
|
||||
var def = $.Deferred();
|
||||
popupDefs.push(def);
|
||||
|
||||
var pop = new form_common.FormViewDialog(self, {
|
||||
res_model: self.field.relation,
|
||||
res_id: resID,
|
||||
context: self.record.context,
|
||||
title: "",
|
||||
on_saved: function (record) {
|
||||
if (record.data.email) {
|
||||
validPartners.push(record.res_id);
|
||||
}
|
||||
},
|
||||
}).open();
|
||||
pop.on('closed', self, function () {
|
||||
def.resolve();
|
||||
var def = new Promise(function (resolve, reject) {
|
||||
var pop = new form_common.FormViewDialog(self, {
|
||||
res_model: self.field.relation,
|
||||
res_id: resID,
|
||||
context: self.record.context,
|
||||
title: "",
|
||||
on_saved: function (record) {
|
||||
if (record.data.email) {
|
||||
validPartners.push(record.res_id);
|
||||
}
|
||||
},
|
||||
}).open();
|
||||
pop.on('closed', self, function () {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
popupDefs.push(def);
|
||||
});
|
||||
return $.when.apply($, popupDefs).then(function() {
|
||||
return Promise.all(popupDefs).then(function() {
|
||||
// All popups have been processed for the given ids
|
||||
// It is now time to set the final value with valid partners ids.
|
||||
validPartners = _.uniq(validPartners);
|
||||
@@ -117,14 +117,14 @@ var FieldMany2ManyTagsEmail = M2MTags.extend({
|
||||
*/
|
||||
_render: function () {
|
||||
var self = this;
|
||||
var def = $.Deferred();
|
||||
var _super = this._super.bind(this);
|
||||
if (this.record.specialData[this.name].invalidPartnerIds.length) {
|
||||
def = this._checkEmailPopup();
|
||||
} else {
|
||||
def.resolve();
|
||||
}
|
||||
return def.then(function () {
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (self.record.specialData[self.name].invalidPartnerIds.length) {
|
||||
resolve(self._checkEmailPopup());
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
}).then(function () {
|
||||
return _super.apply(self, arguments);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -511,7 +511,7 @@ var Message = AbstractMessage.extend(Mixins.EventDispatcherMixin, ServicesMixin
|
||||
* @see {mail.Manager.Notification} for the receipt of 'toggle_star'
|
||||
* notification after this rpc.
|
||||
*
|
||||
* @return {$.Promise}
|
||||
* @return {Promise}
|
||||
*/
|
||||
toggleStarStatus: function () {
|
||||
return this._rpc({
|
||||
|
||||
@@ -150,18 +150,18 @@ var AbstractThread = Class.extend(Mixins.EventDispatcherMixin, {
|
||||
* Mark the thread as read, which resets the unread counter to 0. This is
|
||||
* only performed if the unread counter is not 0.
|
||||
*
|
||||
* @returns {$.Promise}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
markAsRead: function () {
|
||||
if (this._unreadCounter > 0) {
|
||||
return this._markAsRead();
|
||||
}
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
},
|
||||
/**
|
||||
* Post a message on this thread
|
||||
*
|
||||
* @returns {$.Promise} resolved with the message object to be sent to the
|
||||
* @returns {Promise} resolved with the message object to be sent to the
|
||||
* server
|
||||
*/
|
||||
postMessage: function () {
|
||||
@@ -200,22 +200,22 @@ var AbstractThread = Class.extend(Mixins.EventDispatcherMixin, {
|
||||
* Mark the thread as read
|
||||
*
|
||||
* @private
|
||||
* @returns {$.Promise}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_markAsRead: function () {
|
||||
this.resetUnreadCounter();
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
},
|
||||
/**
|
||||
* Post a message on this thread
|
||||
*
|
||||
* @abstract
|
||||
* @private
|
||||
* @returns {$.Promise} resolved with the message object to be sent to the
|
||||
* @returns {Promise} resolved with the message object to be sent to the
|
||||
* server
|
||||
*/
|
||||
_postMessage: function () {
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
},
|
||||
/**
|
||||
* Warn views (e.g. discuss app, thread window, etc.) to update visually
|
||||
|
||||
@@ -70,7 +70,7 @@ var Channel = SearchableThread.extend(ThreadTypingMixin, {
|
||||
this._isMyselfModerator = data.is_moderator;
|
||||
this._lastMessageDate = undefined;
|
||||
this._members = data.members || [];
|
||||
// Deferred that is resolved on fetched members of this channel.
|
||||
// Promise that is resolved on fetched members of this channel.
|
||||
this._membersDef = undefined;
|
||||
// number of messages that are 'needaction', which is equivalent to the
|
||||
// number of messages in this channel that are in inbox.
|
||||
@@ -129,19 +129,21 @@ var Channel = SearchableThread.extend(ThreadTypingMixin, {
|
||||
* @pverride
|
||||
*/
|
||||
detach: function () {
|
||||
this._super.apply(this, arguments);
|
||||
this._rpc({
|
||||
model: 'mail.channel',
|
||||
method: 'channel_minimize',
|
||||
args: [this.getUUID(), true],
|
||||
}, {
|
||||
shadow: true,
|
||||
var self = this;
|
||||
return this._super.apply(this, arguments).then(function () {
|
||||
self._rpc({
|
||||
model: 'mail.channel',
|
||||
method: 'channel_minimize',
|
||||
args: [self.getUUID(), true],
|
||||
}, {
|
||||
shadow: true,
|
||||
});
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Force fetch members of the channel
|
||||
*
|
||||
* @returns {$.Promise<Object[]>} resolved with list of channel listeners
|
||||
* @returns {Promise<Object[]>} resolved with list of channel listeners
|
||||
*/
|
||||
forceFetchMembers: function () {
|
||||
this._membersDef = undefined;
|
||||
@@ -186,7 +188,7 @@ var Channel = SearchableThread.extend(ThreadTypingMixin, {
|
||||
/**
|
||||
* Get listeners of a channel
|
||||
*
|
||||
* @returns {$.Promise<Array<Object[]>>} resolved with list of list of
|
||||
* @returns {Promise<Object[]>} resolved with list of list of
|
||||
* channel listeners.
|
||||
*/
|
||||
getMentionPartnerSuggestions: function () {
|
||||
@@ -302,7 +304,7 @@ var Channel = SearchableThread.extend(ThreadTypingMixin, {
|
||||
* Unsubscribes from channel
|
||||
*
|
||||
* @abstract
|
||||
* @returns {$.Promise} resolve when unsubscribed
|
||||
* @returns {Promise} resolve when unsubscribed
|
||||
*/
|
||||
unsubscribe: function () {},
|
||||
/**
|
||||
@@ -381,19 +383,19 @@ var Channel = SearchableThread.extend(ThreadTypingMixin, {
|
||||
*
|
||||
* @override
|
||||
* @private
|
||||
* @returns {$.Promise} resolved when message has been marked as read
|
||||
* @returns {Promise} resolved when message has been marked as read
|
||||
*/
|
||||
_markAsRead: function () {
|
||||
var superDef = this._super.apply(this, arguments);
|
||||
var seenDef = this._notifySeen();
|
||||
return $.when(superDef, seenDef);
|
||||
return Promise.all([superDef, seenDef]);
|
||||
},
|
||||
/**
|
||||
* @override {mail.model.ThreadTypingMixin}
|
||||
* @private
|
||||
* @param {Object} params
|
||||
* @param {boolean} params.typing
|
||||
* @returns {$.Promise}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_notifyMyselfTyping: function (params) {
|
||||
return this._rpc({
|
||||
@@ -424,7 +426,7 @@ var Channel = SearchableThread.extend(ThreadTypingMixin, {
|
||||
* @override
|
||||
* @private
|
||||
* @param {Object} data data related to the new message
|
||||
* @returns {$.Promise<Object>} resolved when the message has been sent to
|
||||
* @returns {Promise<Object>} resolved when the message has been sent to
|
||||
* the server, with the object message that has been sent to the server.
|
||||
*/
|
||||
_postMessage: function (data) {
|
||||
|
||||
@@ -92,7 +92,7 @@ var DocumentThread = Thread.extend({
|
||||
* @param {Object} options
|
||||
* @param {boolean} [options.forceFetch] if true, fetch anyway, as user
|
||||
* clicked on 'load more'.
|
||||
* @returns {$.Promise<mail.model.Message[]>}
|
||||
* @returns {Promise<mail.model.Message[]>}
|
||||
*/
|
||||
fetchMessages: function (options) {
|
||||
var self = this;
|
||||
@@ -217,14 +217,14 @@ var DocumentThread = Thread.extend({
|
||||
* Get most up to date messageIDs
|
||||
*
|
||||
* @private
|
||||
* @returns {$.Promise} resolved when message IDs have been fetched and set
|
||||
* @returns {Promise} resolved when message IDs have been fetched and set
|
||||
* in the model
|
||||
*/
|
||||
_fetchMessageIDs: function () {
|
||||
var self = this;
|
||||
var resID = this.getDocumentID();
|
||||
if (!resID || !this._mustFetchMessageIDs) {
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
}
|
||||
return this._rpc({
|
||||
model: this.getDocumentModel(),
|
||||
@@ -239,7 +239,7 @@ var DocumentThread = Thread.extend({
|
||||
* @private
|
||||
* @param {Object} options
|
||||
* @param {boolean} [options.forceFetch]
|
||||
* @returns {$.Promise} resolved when messages have been fetched + document
|
||||
* @returns {Promise} resolved when messages have been fetched + document
|
||||
* thread has updated messages
|
||||
*/
|
||||
_fetchMessages: function (options) {
|
||||
@@ -273,7 +273,7 @@ var DocumentThread = Thread.extend({
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
});
|
||||
@@ -284,7 +284,7 @@ var DocumentThread = Thread.extend({
|
||||
*
|
||||
* @override
|
||||
* @private
|
||||
* @returns {$.Promise} resolved when messages have been marked as read on
|
||||
* @returns {Promise} resolved when messages have been marked as read on
|
||||
* the server.
|
||||
*/
|
||||
_markAsRead: function () {
|
||||
@@ -299,7 +299,7 @@ var DocumentThread = Thread.extend({
|
||||
* @override
|
||||
* @private
|
||||
* @param {Object} data data related to the new message
|
||||
* @return {$.Promise<Object>} resolved when the message has been sent to
|
||||
* @return {Promise<Object>} resolved when the message has been sent to
|
||||
* the server, with the object message that has been sent to the server.
|
||||
*/
|
||||
_postMessage: function (data) {
|
||||
|
||||
@@ -34,7 +34,7 @@ var Livechat = TwoUserChannel.extend({
|
||||
* display of a user that is typing.
|
||||
*
|
||||
* @override
|
||||
* @returns {$.Promise<Array<Object[]>>} resolved with list of list of
|
||||
* @returns {Promise<Object[]>} resolved with list of list of
|
||||
* livechat members.
|
||||
*/
|
||||
getMentionPartnerSuggestions: function () {
|
||||
|
||||
@@ -59,7 +59,7 @@ var Mailbox = SearchableThread.extend({
|
||||
* channel, only keep the lastest message of this document/channel in the
|
||||
* previews.
|
||||
*
|
||||
* @returns {$.Promise<Object[]>}
|
||||
* @returns {Promise<Object[]>}
|
||||
*/
|
||||
getMessagePreviews: function () {
|
||||
var self = this;
|
||||
@@ -119,7 +119,7 @@ var Mailbox = SearchableThread.extend({
|
||||
* makes only sense for 'Inbox'.
|
||||
*
|
||||
* @param {Array} domain
|
||||
* @return {$.Promise} resolved when all messages have been marked as read
|
||||
* @return {Promise} resolved when all messages have been marked as read
|
||||
* on the server
|
||||
*/
|
||||
markAllMessagesAsRead: function (domain) {
|
||||
@@ -133,7 +133,7 @@ var Mailbox = SearchableThread.extend({
|
||||
},
|
||||
});
|
||||
}
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
@@ -239,11 +239,11 @@ var ThreadTypingMixin = {
|
||||
* @private
|
||||
* @param {Object} params
|
||||
* @param {boolean} params.typing whether we are typing something or not
|
||||
* @returns {$.Promise} resolved if the server is notified, rejected
|
||||
* @returns {Promise} resolved if the server is notified, rejected
|
||||
* otherwise
|
||||
*/
|
||||
_notifyMyselfTyping: function (params) {
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
},
|
||||
/**
|
||||
* Warn views that the list of users that are currently typing on this
|
||||
|
||||
@@ -56,7 +56,7 @@ var MultiUserChannel = Channel.extend({
|
||||
* Unsubscribes from channel
|
||||
*
|
||||
* @override
|
||||
* @returns {$.Promise} resolve when unsubscribed
|
||||
* @returns {Promise} resolve when unsubscribed
|
||||
*/
|
||||
unsubscribe: function () {
|
||||
return this._rpc({
|
||||
|
||||
@@ -49,7 +49,7 @@ var SearchableThread = Thread.extend({
|
||||
}
|
||||
var cache = this._getCache(domain);
|
||||
if (cache.loaded) {
|
||||
return $.when(cache.messages);
|
||||
return Promise.all(cache.messages);
|
||||
} else {
|
||||
return this._fetchMessages(domain);
|
||||
}
|
||||
@@ -159,7 +159,7 @@ var SearchableThread = Thread.extend({
|
||||
* @private
|
||||
* @param {Array} [pDomain] filter on the messages of the channel
|
||||
* @param {boolean} [loadMore] Whether it should load more message
|
||||
* @return {$.Promise<mail.model.Message[]>} resolved with list of messages
|
||||
* @return {Promise<mail.model.Message[]>} resolved with list of messages
|
||||
*/
|
||||
_fetchMessages: function (pDomain, loadMore) {
|
||||
var self = this;
|
||||
|
||||
@@ -58,12 +58,13 @@ var Thread = AbstractThread.extend(ServicesMixin, {
|
||||
* of this thread. Otherwise unfold it while detaching it.
|
||||
* @param {boolean} [options.passively=false] if set, if the thread window
|
||||
* will be created passively.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
detach: function (options) {
|
||||
options = options || {};
|
||||
this._detached = true;
|
||||
this._folded = options.keepFoldState ? this._folded : false;
|
||||
this._warnUpdatedWindowState({
|
||||
return this._warnUpdatedWindowState({
|
||||
passively: options.passively,
|
||||
});
|
||||
},
|
||||
@@ -79,10 +80,10 @@ var Thread = AbstractThread.extend(ServicesMixin, {
|
||||
* `this.LIMIT` number of messages at a time.
|
||||
*
|
||||
* @abstract
|
||||
* @returns {$.Promise<mail.model.Message[]>}
|
||||
* @returns {Promise<mail.model.Message[]>}
|
||||
*/
|
||||
fetchMessages: function () {
|
||||
return $.when([]);
|
||||
return Promise.resolve([]);
|
||||
},
|
||||
/**
|
||||
* Updates the folded state of the thread. Must be overriden to reflect
|
||||
@@ -110,10 +111,10 @@ var Thread = AbstractThread.extend(ServicesMixin, {
|
||||
* By default, a thread has not listener.
|
||||
*
|
||||
* @abstract
|
||||
* @returns {$.Promise<Array<Object[]>>}
|
||||
* @returns {Promise<Array<Object[]>>}
|
||||
*/
|
||||
getMentionPartnerSuggestions: function () {
|
||||
return $.when([]);
|
||||
return Promise.resolve([]);
|
||||
},
|
||||
/**
|
||||
* Returns the information required to render the preview of this channel.
|
||||
@@ -287,10 +288,10 @@ var Thread = AbstractThread.extend(ServicesMixin, {
|
||||
/**
|
||||
* @abstract
|
||||
* @private
|
||||
* @return {$.Promise}
|
||||
* @return {Promise}
|
||||
*/
|
||||
_fetchMessages: function () {
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
},
|
||||
/**
|
||||
* Replace character representations of emojis by their unicode
|
||||
@@ -330,7 +331,7 @@ var Thread = AbstractThread.extend(ServicesMixin, {
|
||||
* @abstract
|
||||
* @private
|
||||
* @param {Object} data
|
||||
* @returns {$.Promise<Object>} resolved with the message object to be sent
|
||||
* @returns {Promise<Object>} resolved with the message object to be sent
|
||||
* to the server
|
||||
*/
|
||||
_postMessage: function (data) {
|
||||
@@ -355,7 +356,7 @@ var Thread = AbstractThread.extend(ServicesMixin, {
|
||||
messageData.subject = data.subject;
|
||||
}
|
||||
return this._super.apply(this, arguments).then(function () {
|
||||
return $.when(messageData);
|
||||
return messageData;
|
||||
});
|
||||
},
|
||||
/**
|
||||
@@ -374,10 +375,11 @@ var Thread = AbstractThread.extend(ServicesMixin, {
|
||||
* @private
|
||||
* @param {Object} [options={}]
|
||||
* @param {boolean} [options.passively=false]
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_warnUpdatedWindowState: function (options) {
|
||||
options = options || {};
|
||||
this.call('mail_service', 'updateThreadWindow', this.getID(), options);
|
||||
return this.call('mail_service', 'updateThreadWindow', this.getID(), options);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ var TwoUserChannel = Channel.extend({
|
||||
* Unpin from two-user thread
|
||||
*
|
||||
* @override
|
||||
* @returns {$.Promise} resolve when unsubscribed
|
||||
* @returns {Promise} resolve when unsubscribed
|
||||
*/
|
||||
unsubscribe: function () {
|
||||
return this._rpc({
|
||||
|
||||
@@ -182,7 +182,7 @@ MailManager.include({
|
||||
resModel: resModel,
|
||||
});
|
||||
}
|
||||
this._super.apply(this, arguments);
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
/**
|
||||
* Updates the thread windows related to document threads.
|
||||
|
||||
@@ -80,13 +80,14 @@ var MailManager = AbstractService.extend({
|
||||
* the unread_counter of channel.
|
||||
* @param {boolean} [options.silent] whether it should inform in the mailBus
|
||||
* of the newly created message.
|
||||
* @returns {mail.model.Message} message object
|
||||
* @returns {Promise<mail.model.Message>}
|
||||
*/
|
||||
addMessage: function (data, options) {
|
||||
options = options || {};
|
||||
var message = this.getMessage(data.id);
|
||||
var prom = Promise.resolve();
|
||||
if (!message) {
|
||||
message = this._addNewMessage(data, options);
|
||||
prom = this._addNewMessage(data, options);
|
||||
} else {
|
||||
if (data.moderation_status === 'accepted') {
|
||||
message.setModerationStatus('accepted', {
|
||||
@@ -97,7 +98,7 @@ var MailManager = AbstractService.extend({
|
||||
this._addMessageToThreads(message, options);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
return prom;
|
||||
},
|
||||
/**
|
||||
* Creates a channel, can be either a true channel or a DM chat based on
|
||||
@@ -105,7 +106,7 @@ var MailManager = AbstractService.extend({
|
||||
*
|
||||
* @param {integer|string} name id of partner (in case of dm) or name
|
||||
* @param {string} type ['dm_chat', 'public', 'private']
|
||||
* @returns {$.Promise<integer>} resolved with ID of the newly created
|
||||
* @returns {Promise<integer>} resolved with ID of the newly created
|
||||
* channel
|
||||
*/
|
||||
createChannel: function (name, type) {
|
||||
@@ -150,7 +151,7 @@ var MailManager = AbstractService.extend({
|
||||
* Returns the content that will be shown in the mail navbar dropdown
|
||||
*
|
||||
* @param {mail.model.Channel[]} channels
|
||||
* @returns {$.Promise<Object[]>} resolved with list of channel previews
|
||||
* @returns {Promise<Object[]>} resolved with list of channel previews
|
||||
*/
|
||||
getChannelPreviews: function (channels) {
|
||||
var self = this;
|
||||
@@ -227,23 +228,22 @@ var MailManager = AbstractService.extend({
|
||||
*
|
||||
* @param {string} [filter=undefined] specify 'chat' or 'channels' to only
|
||||
* get previews for that type of threads
|
||||
* @returns {$.Promise<Object[]>} resolved with list of objects that have a
|
||||
* @returns {Promise<Object[]>} resolved with list of objects that have a
|
||||
* valid format for rendering a messaging menu preview items.
|
||||
*/
|
||||
getSystrayPreviews: function (filter) {
|
||||
var self = this;
|
||||
var defs = [];
|
||||
|
||||
var channelDef = this._getSystrayChannelPreviews(filter);
|
||||
var inboxDef = this._getSystrayInboxPreviews(filter);
|
||||
var failureDef = this._getSystrayMailFailurePreviews(filter);
|
||||
defs = defs.concat([channelDef, inboxDef, failureDef]);
|
||||
return $.when.apply($, defs)
|
||||
.then(function (previewsChannel, previewsInbox, previewsFailure) {
|
||||
|
||||
return Promise.all([channelDef, inboxDef, failureDef])
|
||||
.then(function (result) { //previewsChannel, previewsInbox, previewsFailure
|
||||
// order: failures > inbox > channel, each group must be sorted
|
||||
previewsChannel = self._sortPreviews(previewsChannel);
|
||||
previewsInbox = self._sortPreviews(previewsInbox);
|
||||
previewsFailure = self._sortPreviews(previewsFailure);
|
||||
var previewsChannel = self._sortPreviews(result[0]);
|
||||
var previewsInbox = self._sortPreviews(result[1]);
|
||||
var previewsFailure = self._sortPreviews(result[2]);
|
||||
return _.union(previewsFailure, previewsInbox, previewsChannel);
|
||||
});
|
||||
},
|
||||
@@ -295,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 {Promise}
|
||||
*/
|
||||
isReady: function () {
|
||||
return this._isReady;
|
||||
@@ -306,24 +306,24 @@ var MailManager = AbstractService.extend({
|
||||
*
|
||||
* @param {integer} channelID
|
||||
* @param {Object} [options] options to be passed on channel add
|
||||
* @returns {$.Promise<integer>} resolved with channelID joined
|
||||
* @returns {Promise<integer>} resolved with channelID joined
|
||||
*/
|
||||
joinChannel: function (channelID, options) {
|
||||
var def;
|
||||
var prom;
|
||||
var channel = this.getChannel(channelID);
|
||||
if (channel) {
|
||||
// channel already joined
|
||||
def = $.when(channelID);
|
||||
prom = Promise.resolve(channelID);
|
||||
} else {
|
||||
def = this._joinAndAddChannel(channelID, options);
|
||||
prom = this._joinAndAddChannel(channelID, options);
|
||||
}
|
||||
return def;
|
||||
return prom;
|
||||
},
|
||||
/**
|
||||
* Mark messages as read
|
||||
*
|
||||
* @param {Array} messageIDs list of messages IDs
|
||||
* @returns {$.Promise} resolved when messages have been marked as read on
|
||||
* @returns {Promise} resolved when messages have been marked as read on
|
||||
* the server.
|
||||
*/
|
||||
markMessagesAsRead: function (messageIDs) {
|
||||
@@ -341,7 +341,7 @@ var MailManager = AbstractService.extend({
|
||||
args: [ids],
|
||||
});
|
||||
} else {
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
}
|
||||
},
|
||||
/**
|
||||
@@ -396,19 +396,19 @@ var MailManager = AbstractService.extend({
|
||||
*
|
||||
* @param {string} searchVal
|
||||
* @param {integer} limit max number of found partners in the response
|
||||
* @returns {$.Promise<Object[]>} list of found partners (matching
|
||||
* @returns {Promise<Object[]>} list of found partners (matching
|
||||
* 'searchVal')
|
||||
*/
|
||||
searchPartner: function (searchVal, limit) {
|
||||
var def = $.Deferred();
|
||||
var self = this;
|
||||
var partners = this._searchPartnerPrefetch(searchVal, limit);
|
||||
|
||||
if (!partners.length) {
|
||||
def = this._searchPartnerFetch(searchVal, limit);
|
||||
} else {
|
||||
def = $.when(partners);
|
||||
}
|
||||
return def.then(function (partners) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (!partners.length) {
|
||||
resolve(self._searchPartnerFetch(searchVal, limit));
|
||||
} else {
|
||||
resolve(partners);
|
||||
}
|
||||
}).then(function (partners) {
|
||||
var suggestions = _.map(partners, function (partner) {
|
||||
return {
|
||||
id: partner.id,
|
||||
@@ -422,7 +422,7 @@ var MailManager = AbstractService.extend({
|
||||
/**
|
||||
* Unstars all messages from all channels
|
||||
*
|
||||
* @returns {$.Promise}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
unstarAll: function () {
|
||||
return this._rpc({
|
||||
@@ -448,11 +448,13 @@ var MailManager = AbstractService.extend({
|
||||
* @param {string} [data.state] e.g. 'open', 'folded'
|
||||
* @param {Object|integer} [options=undefined]
|
||||
* @param {boolean} [options.silent=false]
|
||||
* @returns {integer} the ID of the newly or already existing channel
|
||||
* @returns {Promise<integer>} resolves with the ID of the newly or already
|
||||
* existing channel
|
||||
*/
|
||||
_addChannel: function (data, options) {
|
||||
options = typeof options === 'object' ? options : {};
|
||||
var channel = this.getChannel(data.id);
|
||||
var proms = [];
|
||||
if (!channel) {
|
||||
channel = this._makeChannel(data, options);
|
||||
if (channel.getType() === 'dm_chat') {
|
||||
@@ -462,14 +464,16 @@ var MailManager = AbstractService.extend({
|
||||
if (data.last_message) {
|
||||
// channel_info in mobile, necessary for showing channel
|
||||
// preview in mobile
|
||||
this.addMessage(data.last_message);
|
||||
proms.push(this.addMessage(data.last_message));
|
||||
}
|
||||
this._sortThreads();
|
||||
if (!options.silent) {
|
||||
this._mailBus.trigger('new_channel', channel);
|
||||
this._mailBus.trigger('new_channel', channel, proms);
|
||||
}
|
||||
}
|
||||
return channel.getID();
|
||||
return Promise.all(proms).then(function () {
|
||||
return channel.getID();
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Add a new mailbox
|
||||
@@ -516,21 +520,23 @@ var MailManager = AbstractService.extend({
|
||||
* @private
|
||||
* @param {Object} data
|
||||
* @param {Object} options
|
||||
* @returns {mail.model.Message}
|
||||
* @return {Promise<mail.model.Message>}
|
||||
*/
|
||||
_addNewMessage: function (data, options) {
|
||||
var self = this;
|
||||
var message = this._makeMessage(data);
|
||||
// Keep the array ordered by ID when inserting the new message
|
||||
var index = _.sortedIndex(this._messages, message, function (msg) {
|
||||
return msg.getID();
|
||||
});
|
||||
this._messages.splice(index, 0, message);
|
||||
this._addNewMessagePostprocessThread(message, options);
|
||||
this._addMessageToThreads(message, options);
|
||||
if (!options.silent) {
|
||||
this._mailBus.trigger('new_message', message);
|
||||
}
|
||||
return message;
|
||||
return this._addNewMessagePostprocessThread(message, options).then(function () {
|
||||
self._addMessageToThreads(message, options);
|
||||
if (!options.silent) {
|
||||
self._mailBus.trigger('new_message', message);
|
||||
}
|
||||
return message;
|
||||
});
|
||||
},
|
||||
/**
|
||||
* For newly added message, postprocess threads linked to this message
|
||||
@@ -541,9 +547,11 @@ var MailManager = AbstractService.extend({
|
||||
* @param {Array} [options.domain]
|
||||
* @param {boolean} [options.incrementUnread]
|
||||
* @param {boolean} [options.showNotification]
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_addNewMessagePostprocessThread: function (message, options) {
|
||||
var self = this;
|
||||
var proms = [];
|
||||
_.each(message.getThreadIDs(), function (threadID) {
|
||||
var thread = self.getThread(threadID);
|
||||
if (thread) {
|
||||
@@ -553,6 +561,7 @@ var MailManager = AbstractService.extend({
|
||||
!message.isSystemNotification()
|
||||
) {
|
||||
if (thread.isTwoUserThread() && options.showNotification) {
|
||||
var prom = Promise.resolve();
|
||||
if (
|
||||
!self._isDiscussOpen() &&
|
||||
!config.device.isMobile &&
|
||||
@@ -560,17 +569,21 @@ var MailManager = AbstractService.extend({
|
||||
) {
|
||||
// automatically open thread window
|
||||
// while keeping it unread
|
||||
thread.detach({ passively: true });
|
||||
}
|
||||
var query = { isVisible: false };
|
||||
self._mailBus.trigger('is_thread_bottom_visible', thread, query);
|
||||
if (!self.call('bus_service', 'isOdooFocused') || !query.isVisible) {
|
||||
self._notifyIncomingMessage(message);
|
||||
prom = thread.detach({ passively: true });
|
||||
}
|
||||
proms.push(prom);
|
||||
prom.then(function () {
|
||||
var query = { isVisible: false };
|
||||
self._mailBus.trigger('is_thread_bottom_visible', thread, query);
|
||||
if (!self.call('bus_service', 'isOdooFocused') || !query.isVisible) {
|
||||
self._notifyIncomingMessage(message);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return Promise.all(proms);
|
||||
},
|
||||
/**
|
||||
* Create a Channel (other than a DM)
|
||||
@@ -578,7 +591,7 @@ var MailManager = AbstractService.extend({
|
||||
* @private
|
||||
* @param {string} name
|
||||
* @param {string} type
|
||||
* @returns {$.Promise<integer>} ID of the created channel
|
||||
* @returns {Promise<integer>} ID of the created channel
|
||||
*/
|
||||
_createChannel: function (name, type) {
|
||||
var context = _.extend({ isMobile: config.device.isMobile }, session.user_context);
|
||||
@@ -595,7 +608,7 @@ var MailManager = AbstractService.extend({
|
||||
*
|
||||
* @private
|
||||
* @param {string} name
|
||||
* @returns {$.Promise<integer>} ID of the created channel
|
||||
* @returns {Promise<integer>} ID of the created channel
|
||||
*/
|
||||
_createDMChat: function (name) {
|
||||
var context = _.extend({ isMobile: config.device.isMobile }, session.user_context);
|
||||
@@ -610,7 +623,7 @@ var MailManager = AbstractService.extend({
|
||||
/**
|
||||
* @private
|
||||
* @param {integer[]} channelIDs
|
||||
* @returns {$.Promise<Object[]>} resolved with list of channel preview
|
||||
* @returns {Promise<Object[]>} resolved with list of channel preview
|
||||
*/
|
||||
_fetchChannelPreviews: function (channelIDs) {
|
||||
return this._rpc({
|
||||
@@ -652,7 +665,7 @@ var MailManager = AbstractService.extend({
|
||||
*
|
||||
* @private
|
||||
* @param {mail.model.Channel[]} channels
|
||||
* @returns {$.Deferred<Object[]>} resolved with list of channel previews
|
||||
* @returns {Promise<Object[]>} resolved with list of channel previews
|
||||
*/
|
||||
_getChannelPreviews: function (channels) {
|
||||
var self = this;
|
||||
@@ -667,19 +680,22 @@ var MailManager = AbstractService.extend({
|
||||
});
|
||||
fetchDef = this._fetchChannelPreviews(ids);
|
||||
} else {
|
||||
fetchDef = $.when();
|
||||
fetchDef = Promise.resolve();
|
||||
}
|
||||
return fetchDef.then(function (fetchedPreviews) {
|
||||
// add fetched messages
|
||||
var proms = [];
|
||||
_.each(fetchedPreviews, function (fetchedPreview) {
|
||||
if (fetchedPreview.last_message) {
|
||||
self.addMessage(fetchedPreview.last_message);
|
||||
proms.push(self.addMessage(fetchedPreview.last_message));
|
||||
}
|
||||
// mark the channel as previewed, so that we do not need to
|
||||
// fetch preview again
|
||||
var channel = self.getChannel(fetchedPreview.id);
|
||||
channel.markAsPreviewed();
|
||||
});
|
||||
return Promise.all(proms);
|
||||
}).then(function () {
|
||||
return _.map(channels, function (channel) {
|
||||
return channel.getPreview();
|
||||
});
|
||||
@@ -694,7 +710,7 @@ var MailManager = AbstractService.extend({
|
||||
* the documentID is omitted for a model preview, whereas it is set for a
|
||||
* preview of a failure related to a document.
|
||||
*
|
||||
* @returns {$.Promise<Object[]>} resolved with previews of mail failures
|
||||
* @returns {Promise<Object[]>} resolved with previews of mail failures
|
||||
*/
|
||||
_getMailFailurePreviews: function () {
|
||||
// items = list of objects:
|
||||
@@ -754,7 +770,7 @@ var MailManager = AbstractService.extend({
|
||||
* @private
|
||||
* @param {string|undefined} [filter] the filter to apply on channel
|
||||
* previews in systray messaging menu
|
||||
* @returns {$.Promise<Object[]>} resolved with object valid for template
|
||||
* @returns {Promise<Object[]>} resolved with object valid for template
|
||||
* mail.Preview on channel previews, based on selected filter
|
||||
*/
|
||||
_getSystrayChannelPreviews: function (filter) {
|
||||
@@ -796,7 +812,7 @@ var MailManager = AbstractService.extend({
|
||||
*
|
||||
* @private
|
||||
* @param {string|undefined} [filter]
|
||||
* @returns {$.Deferred<Object[]>} resolved with valid objects for template
|
||||
* @returns {Promise<Object[]>} resolved with valid objects for template
|
||||
* mail.Preview on inbox message previews
|
||||
*/
|
||||
_getSystrayInboxPreviews: function (filter) {
|
||||
@@ -806,7 +822,7 @@ var MailManager = AbstractService.extend({
|
||||
var inbox = this.getMailbox('inbox');
|
||||
return inbox.getMessagePreviews();
|
||||
} else {
|
||||
return $.when([]);
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
},
|
||||
/**
|
||||
@@ -820,7 +836,7 @@ var MailManager = AbstractService.extend({
|
||||
if (filter === 'mailbox_inbox' || !filter) {
|
||||
return this._getMailFailurePreviews();
|
||||
} else {
|
||||
return $.when([]);
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
},
|
||||
/**
|
||||
@@ -863,7 +879,7 @@ var MailManager = AbstractService.extend({
|
||||
* @private
|
||||
* @param {integer|string} channelID
|
||||
* @param {Object} options options passed on channel add
|
||||
* @returns {$.Promise<integer>} channelID of joined and added channel
|
||||
* @returns {Promise<integer>} channelID of joined and added channel
|
||||
*/
|
||||
_joinAndAddChannel: function (channelID, options) {
|
||||
var self = this;
|
||||
@@ -941,7 +957,7 @@ var MailManager = AbstractService.extend({
|
||||
this._toNotifyChannelFetchedIDs = [];
|
||||
if (_.isEmpty(channelIDs)) {
|
||||
// no channel to notify fetched
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
}
|
||||
return this._rpc({
|
||||
model: 'mail.channel',
|
||||
@@ -1098,7 +1114,7 @@ var MailManager = AbstractService.extend({
|
||||
* @private
|
||||
* @param {string} searchVal
|
||||
* @param {integer} limit
|
||||
* @returns {$.Promise<Object[]>} fetched partners matching 'searchVal'
|
||||
* @returns {Promise<Object[]>} fetched partners matching 'searchVal'
|
||||
*/
|
||||
_searchPartnerFetch: function (searchVal, limit) {
|
||||
return this._rpc({
|
||||
@@ -1194,12 +1210,17 @@ var MailManager = AbstractService.extend({
|
||||
* (e.g. list of public channel data are stored in 'channel_channel')
|
||||
* @param {Object[]} [data.channel_slots[i] list of data of channel of type
|
||||
* `i`
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_updateChannelsFromServer: function (data) {
|
||||
var self = this;
|
||||
var proms = [];
|
||||
_.each(data.channel_slots, function (channels) {
|
||||
_.each(channels, self._addChannel.bind(self));
|
||||
_.each(channels, function (channel) {
|
||||
proms.push(self._addChannel(channel));
|
||||
});
|
||||
});
|
||||
return Promise.all(proms);
|
||||
},
|
||||
/**
|
||||
* Update commands from mail data fetched from the server
|
||||
@@ -1221,11 +1242,12 @@ var MailManager = AbstractService.extend({
|
||||
* @param {Array<Object[]>} result.mention_partner_suggestions list of
|
||||
* suggestions.
|
||||
* @param {integer} result.menu_id the menu ID of discuss app
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_updateInternalStateFromServer: function (result) {
|
||||
// commands are needed for channel instantiation
|
||||
this._updateCommandsFromServer(result);
|
||||
this._updateChannelsFromServer(result);
|
||||
var prom = this._updateChannelsFromServer(result);
|
||||
this._updateModerationSettingsFromServer(result);
|
||||
this._updateMailboxesFromServer(result);
|
||||
this._updateMailFailuresFromServer(result);
|
||||
@@ -1233,6 +1255,8 @@ var MailManager = AbstractService.extend({
|
||||
|
||||
this._mentionPartnerSuggestions = result.mention_partner_suggestions;
|
||||
this._discussMenuID = result.menu_id;
|
||||
|
||||
return prom;
|
||||
},
|
||||
/**
|
||||
* Update the mailboxes with mail data fetched from server, namely 'Inbox',
|
||||
|
||||
@@ -101,12 +101,12 @@ MailManager.include({
|
||||
channelAlreadyInCache = !!this.getChannel(messageData.channel_ids[0]);
|
||||
def = this.joinChannel(messageData.channel_ids[0], { autoswitch: false });
|
||||
} else {
|
||||
def = $.when();
|
||||
def = Promise.resolve();
|
||||
}
|
||||
def.then(function () {
|
||||
// don't increment unread if channel wasn't in cache yet as
|
||||
// its unread counter has just been fetched
|
||||
self.addMessage(messageData, {
|
||||
return self.addMessage(messageData, {
|
||||
showNotification: true,
|
||||
incrementUnread: channelAlreadyInCache
|
||||
});
|
||||
@@ -179,18 +179,19 @@ MailManager.include({
|
||||
_handleNeedactionNotification: function (messageData) {
|
||||
var self = this;
|
||||
var inbox = this.getMailbox('inbox');
|
||||
var message = this.addMessage(messageData, {
|
||||
this.addMessage(messageData, {
|
||||
incrementUnread: true,
|
||||
showNotification: true,
|
||||
}).then(function (message) {
|
||||
inbox.incrementMailboxCounter();
|
||||
_.each(message.getThreadIDs(), function (threadID) {
|
||||
var channel = self.getChannel(threadID);
|
||||
if (channel) {
|
||||
channel.incrementNeedactionCounter();
|
||||
}
|
||||
});
|
||||
self._mailBus.trigger('update_needaction', inbox.getMailboxCounter());
|
||||
});
|
||||
inbox.incrementMailboxCounter();
|
||||
_.each(message.getThreadIDs(), function (threadID) {
|
||||
var channel = self.getChannel(threadID);
|
||||
if (channel) {
|
||||
channel.incrementNeedactionCounter();
|
||||
}
|
||||
});
|
||||
this._mailBus.trigger('update_needaction', inbox.getMailboxCounter());
|
||||
},
|
||||
/**
|
||||
* Called when an activity record has been updated on the server
|
||||
@@ -381,8 +382,10 @@ MailManager.include({
|
||||
* @param {Object} data.message data of message
|
||||
*/
|
||||
_handlePartnerMessageModeratorNotification: function (data) {
|
||||
this.addMessage(data.message);
|
||||
this._mailBus.trigger('update_moderation_counter');
|
||||
var self = this;
|
||||
this.addMessage(data.message).then(function () {
|
||||
self._mailBus.trigger('update_moderation_counter');
|
||||
});
|
||||
},
|
||||
/**
|
||||
* On receiving a notification that is specific to a user
|
||||
|
||||
@@ -81,7 +81,7 @@ MailManager.include({
|
||||
var self = this;
|
||||
var partnerIDs = data.partnerIDs;
|
||||
if (_.isEmpty(partnerIDs)) {
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
}
|
||||
return this._rpc({
|
||||
model: 'res.partner',
|
||||
|
||||
@@ -94,6 +94,7 @@ MailManager.include({
|
||||
* is not open yet, and do nothing otherwise.
|
||||
* @param {boolean} [options.keepFoldState=false] if set to true, keep the
|
||||
* fold state of the thread
|
||||
* @returns {Promise}
|
||||
*/
|
||||
openThreadWindow: function (threadID, options) {
|
||||
var self = this;
|
||||
@@ -108,10 +109,10 @@ MailManager.include({
|
||||
return;
|
||||
}
|
||||
var threadWindow = this._getThreadWindow(threadID);
|
||||
var def = $.when();
|
||||
var prom = Promise.resolve();
|
||||
if (!threadWindow) {
|
||||
thread.isCreatingWindow = true;
|
||||
def = thread.fetchMessages().then(function () {
|
||||
prom = thread.fetchMessages().then(function () {
|
||||
threadWindow = self._makeNewThreadWindow(thread, options);
|
||||
self._placeNewThreadWindow(threadWindow, options.passively);
|
||||
return threadWindow.appendTo($(self.THREAD_WINDOW_APPENDTO));
|
||||
@@ -126,12 +127,12 @@ MailManager.include({
|
||||
) {
|
||||
thread.markAsRead();
|
||||
}
|
||||
}).fail(function () {
|
||||
thread.isCreatingWindow = false;
|
||||
}).guardedCatch(function () {
|
||||
// thread window could not be open, which may happen due to
|
||||
// access error while fetching messages to the document.
|
||||
// abort opening the thread window in this case.
|
||||
thread.close();
|
||||
}).always(function () {
|
||||
thread.isCreatingWindow = false;
|
||||
});
|
||||
} else if (!options.passively) {
|
||||
@@ -139,7 +140,7 @@ MailManager.include({
|
||||
this._makeThreadWindowVisible(threadWindow);
|
||||
}
|
||||
}
|
||||
def.then(function () {
|
||||
return prom.then(function () {
|
||||
threadWindow.updateVisualFoldState();
|
||||
});
|
||||
},
|
||||
@@ -155,14 +156,16 @@ MailManager.include({
|
||||
*/
|
||||
updateThreadWindow: function (threadID, options) {
|
||||
var thread = this.getThread(threadID);
|
||||
var prom = Promise.resolve();
|
||||
if (thread) {
|
||||
if (thread.isDetached()) {
|
||||
_.extend(options, { keepFoldState: true });
|
||||
this.openThreadWindow(threadID, options);
|
||||
prom = this.openThreadWindow(threadID, options);
|
||||
} else {
|
||||
this._closeThreadWindow(threadID);
|
||||
}
|
||||
}
|
||||
return prom;
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -429,7 +432,7 @@ MailManager.include({
|
||||
*
|
||||
* @private
|
||||
* @param {integer} partnerID
|
||||
* @returns {$.Promise<integer>} resolved with ID of the DM chat
|
||||
* @returns {Promise<integer>} resolved with ID of the DM chat
|
||||
*/
|
||||
_openAndDetachDMChat: function (partnerID) {
|
||||
return this._rpc({
|
||||
@@ -647,10 +650,16 @@ MailManager.include({
|
||||
*
|
||||
* @private
|
||||
* @param {mail.model.Channel} channel
|
||||
* @param {Promise[]} proms used to synchronize async operations on the
|
||||
* channel (like the rendering of its window)
|
||||
*/
|
||||
_onNewChannel: function (channel) {
|
||||
_onNewChannel: function (channel, proms) {
|
||||
if (channel.isDetached()) {
|
||||
this.openThreadWindow(channel.getID(), { keepFoldState: true, passively: true });
|
||||
var prom = this.openThreadWindow(channel.getID(), {
|
||||
keepFoldState: true,
|
||||
passively: true,
|
||||
});
|
||||
proms.push(prom);
|
||||
} else {
|
||||
this._closeThreadWindow(channel.getID());
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ var ActivityMenu = Widget.extend({
|
||||
'show.bs.dropdown': '_onActivityMenuShow',
|
||||
},
|
||||
willStart: function () {
|
||||
return $.when(this.call('mail_service', 'isReady'));
|
||||
return Promise.resolve(this.call('mail_service', 'isReady'));
|
||||
},
|
||||
start: function () {
|
||||
this._$activitiesPreview = this.$('.o_mail_systray_dropdown_items');
|
||||
|
||||
@@ -30,7 +30,7 @@ var MessagingMenu = Widget.extend({
|
||||
* @override
|
||||
*/
|
||||
willStart: function () {
|
||||
return $.when(this._super.apply(this, arguments), this.call('mail_service', 'isReady'));
|
||||
return Promise.all([this._super.apply(this, arguments), this.call('mail_service', 'isReady')]);
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
@@ -112,7 +112,7 @@ var MessagingMenu = Widget.extend({
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {$.Promise<Object[]>} resolved with list of previews that are
|
||||
* @returns {Promise<Object[]>} resolved with list of previews that are
|
||||
* compatible with the 'mail.Preview' template.
|
||||
*/
|
||||
_getPreviews: function () {
|
||||
|
||||
@@ -57,7 +57,7 @@ var ThreadField = AbstractField.extend({
|
||||
var def1 = this._threadWidget.appendTo(this.$el);
|
||||
var def2 = this._super.apply(this, arguments);
|
||||
|
||||
return this.alive($.when(def1, def2)).then(function () {
|
||||
return this.alive(Promise.all([def1, def2])).then(function () {
|
||||
// unwrap the thread to remove an unnecessary level on div
|
||||
self.setElement(self._threadWidget.$el);
|
||||
var mailBus = self.call('mail_service', 'getMailBus');
|
||||
@@ -86,7 +86,7 @@ var ThreadField = AbstractField.extend({
|
||||
/**
|
||||
* @param {Object} message
|
||||
* @param {integer[]} message.partner_ids
|
||||
* @return {$.Promise}
|
||||
* @return {Promise}
|
||||
*/
|
||||
postMessage: function (message) {
|
||||
var self = this;
|
||||
@@ -95,9 +95,9 @@ var ThreadField = AbstractField.extend({
|
||||
if (message.partner_ids.length) {
|
||||
self.trigger_up('reload_mail_fields', { followers: true });
|
||||
}
|
||||
})
|
||||
.fail(function () {
|
||||
}).guardedCatch(function () {
|
||||
self.do_notify(_t("Sending Error"), _t("Your message has not been sent."));
|
||||
return Promise.reject();
|
||||
});
|
||||
},
|
||||
|
||||
@@ -109,7 +109,7 @@ var ThreadField = AbstractField.extend({
|
||||
* @private
|
||||
* @param {Object} [options]
|
||||
* @param {boolean} [options.forceFetch]
|
||||
* @return {$.Deferred}
|
||||
* @return {Promise}
|
||||
*/
|
||||
_fetchAndRenderThread: function (options) {
|
||||
var self = this;
|
||||
@@ -117,7 +117,7 @@ var ThreadField = AbstractField.extend({
|
||||
var thread = new CreateModeDocumentThread();
|
||||
options = { isCreateMode: true };
|
||||
self._threadWidget.render(thread, options);
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
var fetchDef = this.dp.add(this._documentThread.fetchMessages(options));
|
||||
return fetchDef.then(function () {
|
||||
@@ -134,7 +134,7 @@ var ThreadField = AbstractField.extend({
|
||||
/**
|
||||
* @override
|
||||
* @private
|
||||
* @returns {$.Deferred}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_render: function () {
|
||||
return this._fetchAndRenderThread();
|
||||
|
||||
@@ -248,16 +248,16 @@ var ThreadWidget = Widget.extend({
|
||||
*/
|
||||
removeMessageAndRender: function (messageID, thread, options) {
|
||||
var self = this;
|
||||
var done = $.Deferred();
|
||||
this.$('.o_thread_message[data-message-id="' + messageID + '"]')
|
||||
return new Promise(function (resolve, reject) {
|
||||
self.$('.o_thread_message[data-message-id="' + messageID + '"]')
|
||||
.fadeOut({
|
||||
done: function () {
|
||||
self.render(thread, options);
|
||||
done.resolve();
|
||||
resolve();
|
||||
},
|
||||
duration: 200,
|
||||
});
|
||||
return done;
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Scroll to the bottom of the thread
|
||||
@@ -273,7 +273,7 @@ var ThreadWidget = Widget.extend({
|
||||
* @param {boolean} [options.onlyIfNecessary]
|
||||
*/
|
||||
scrollToMessage: function (options) {
|
||||
var $target = this.$('.o_thread_message[data-message-id="' + options.msgID + '"]');
|
||||
var $target = this.$('.o_thread_message[data-message-id="' + options.messageID + '"]');
|
||||
if (options.onlyIfNecessary) {
|
||||
var delta = $target.parent().height() - $target.height();
|
||||
var offset = delta < 0 ?
|
||||
|
||||
@@ -95,7 +95,7 @@ var AbstractThreadWindow = Widget.extend({
|
||||
var def = this._threadWidget.replace(this.$('.o_thread_window_content')).then(function () {
|
||||
self._threadWidget.$el.on('scroll', self, self._debouncedOnScroll);
|
||||
});
|
||||
return $.when(this._super(), def);
|
||||
return Promise.all([this._super(), def]);
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
|
||||
@@ -83,7 +83,7 @@ var ThreadWindow = AbstractThreadWindow.extend({
|
||||
}
|
||||
this._updateOutOfOfficeReadMoreLessButton();
|
||||
|
||||
return $.when(superDef, composerDef);
|
||||
return Promise.all([superDef, composerDef]);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -241,7 +241,7 @@ var ThreadWindow = AbstractThreadWindow.extend({
|
||||
autoFocus: true,
|
||||
source: function (request, response) {
|
||||
self.call('mail_service', 'searchPartner', request.term, 10)
|
||||
.done(response);
|
||||
.then(response);
|
||||
},
|
||||
select: function (event, ui) {
|
||||
// remember partner ID so that we can replace this window
|
||||
|
||||
@@ -19,7 +19,7 @@ var ActivityModel = AbstractModel.extend({
|
||||
* @override
|
||||
* @param {Object} params
|
||||
* @param {Array[]} params.domain
|
||||
* @returns {Deferred}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
load: function (params) {
|
||||
this.domain = params.domain;
|
||||
@@ -31,7 +31,7 @@ var ActivityModel = AbstractModel.extend({
|
||||
* @param {any} handle
|
||||
* @param {Object} params
|
||||
* @param {Array[]} params.domain
|
||||
* @returns {Deferred}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
reload: function (handle, params) {
|
||||
if (params && 'domain' in params) {
|
||||
@@ -48,7 +48,7 @@ var ActivityModel = AbstractModel.extend({
|
||||
* Fetch activity data.
|
||||
*
|
||||
* @private
|
||||
* @returns {Deferred}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_fetchData: function () {
|
||||
var self = this;
|
||||
|
||||
@@ -5,8 +5,8 @@ var AbstractRenderer = require('web.AbstractRenderer');
|
||||
var core = require('web.core');
|
||||
var field_registry = require('web.field_registry');
|
||||
|
||||
var QWeb = core.qweb;
|
||||
var _t = core._t;
|
||||
var QWeb = core.qweb;
|
||||
|
||||
var ActivityRenderer = AbstractRenderer.extend({
|
||||
className: 'o_activity_view',
|
||||
@@ -125,21 +125,22 @@ var ActivityRenderer = AbstractRenderer.extend({
|
||||
};
|
||||
var KanbanActivity = field_registry.get('kanban_activity');
|
||||
var widget = new KanbanActivity(self, "activity_ids", record, {});
|
||||
widget.appendTo($td);
|
||||
// replace clock by closest deadline
|
||||
var $date = $('<div>');
|
||||
var formated_date = moment(activity_group.o_closest_deadline).format('ll');
|
||||
var current_year = (new Date()).getFullYear();
|
||||
if (formated_date.endsWith(current_year)) { // Dummy logic to remove year (only if current year), we will maybe need to improve it
|
||||
formated_date = formated_date.slice(0, -4);
|
||||
formated_date = formated_date.replace(/( |,)*$/g, "");
|
||||
}
|
||||
$date
|
||||
.text(formated_date)
|
||||
.addClass('o_closest_deadline');
|
||||
$td.find('a')
|
||||
.empty()
|
||||
.append($date);
|
||||
widget.appendTo($td).then(function() {
|
||||
// replace clock by closest deadline
|
||||
var $date = $('<div>');
|
||||
var formated_date = moment(activity_group.o_closest_deadline).format('ll');
|
||||
var current_year = (new Date()).getFullYear();
|
||||
if (formated_date.endsWith(current_year)) { // Dummy logic to remove year (only if current year), we will maybe need to improve it
|
||||
formated_date = formated_date.slice(0, -4);
|
||||
formated_date = formated_date.replace(/( |,)*$/g, "");
|
||||
}
|
||||
$date
|
||||
.text(formated_date)
|
||||
.addClass('o_closest_deadline');
|
||||
$td.find('a')
|
||||
.empty()
|
||||
.append($date);
|
||||
});
|
||||
return $td;
|
||||
});
|
||||
var $tr = $('<tr/>', {class: 'o_data_row'})
|
||||
|
||||
@@ -162,19 +162,19 @@ QUnit.module('activity view', {
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test('activity view: simple activity rendering', function (assert) {
|
||||
QUnit.test('activity view: simple activity rendering', async function (assert) {
|
||||
assert.expect(7);
|
||||
var activity = createView({
|
||||
var activity = await createView({
|
||||
View: ActivityView,
|
||||
model: 'task',
|
||||
data: this.data,
|
||||
arch: '<activity string="Task"/>',
|
||||
mockRPC: function(route, args) {
|
||||
if (args.method === 'get_activity_data') {
|
||||
return $.when(ACTIVITY_DATA);
|
||||
return Promise.resolve(ACTIVITY_DATA);
|
||||
}
|
||||
return this._super(route, args);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
assert.containsOnce(activity, 'table',
|
||||
@@ -194,16 +194,16 @@ QUnit.test('activity view: simple activity rendering', function (assert) {
|
||||
activity.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('activity view: no content rendering', function (assert) {
|
||||
QUnit.test('activity view: no content rendering', async function (assert) {
|
||||
assert.expect(2);
|
||||
var activity = createView({
|
||||
var activity = await createView({
|
||||
View: ActivityView,
|
||||
model: 'task',
|
||||
data: this.data,
|
||||
arch: '<activity string="Task"/>',
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'get_activity_data') {
|
||||
return $.when({ activity_types: [] });
|
||||
return Promise.resolve({ activity_types: [] });
|
||||
}
|
||||
return this._super(route, args);
|
||||
},
|
||||
@@ -218,20 +218,20 @@ QUnit.test('activity view: no content rendering', function (assert) {
|
||||
activity.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('activity view: batch send mail on activity', function (assert) {
|
||||
QUnit.test('activity view: batch send mail on activity', async function (assert) {
|
||||
assert.expect(6);
|
||||
var activity = createView({
|
||||
var activity = await createView({
|
||||
View: ActivityView,
|
||||
model: 'task',
|
||||
data: this.data,
|
||||
arch: '<activity string="Task"/>',
|
||||
mockRPC: function(route, args) {
|
||||
if (args.method === 'activity_send_mail'){
|
||||
assert.step(args.args);
|
||||
return $.when();
|
||||
assert.step(JSON.stringify(args.args));
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (args.method === 'get_activity_data') {
|
||||
return $.when(ACTIVITY_DATA);
|
||||
return Promise.resolve(ACTIVITY_DATA);
|
||||
}
|
||||
return this._super(route, args);
|
||||
},
|
||||
@@ -250,16 +250,16 @@ QUnit.test('activity view: batch send mail on activity', function (assert) {
|
||||
testUtils.dom.click(activity.$('table thead tr:first th:nth-child(2) span:nth-child(2) i.fa-ellipsis-v'));
|
||||
testUtils.dom.click(activity.$('table thead tr:first th:nth-child(2) span:nth-child(2) .dropdown-menu.show .o_send_mail_template:nth-child(2):contains(Task: Reception Acknowledgment)'));
|
||||
assert.verifySteps([
|
||||
[[13, 30], 9], //send mail template 9 on tasl 13 and 30
|
||||
[[13, 30], 8] //send mail template 8 on tasl 13 and 30
|
||||
'[[13,30],9]', // send mail template 9 on tasks 13 and 30
|
||||
'[[13,30],8]', // send mail template 8 on tasks 13 and 30
|
||||
]);
|
||||
|
||||
activity.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('activity view: activity widget', function (assert) {
|
||||
QUnit.test('activity view: activity widget', async function (assert) {
|
||||
assert.expect(16);
|
||||
var activity = createView({
|
||||
var activity = await createView({
|
||||
View: ActivityView,
|
||||
model: 'task',
|
||||
data: this.data,
|
||||
@@ -268,16 +268,16 @@ QUnit.test('activity view: activity widget', function (assert) {
|
||||
if (args.method === 'activity_send_mail'){
|
||||
assert.deepEqual([[30],8],args.args, "Should send template 8 on record 30");
|
||||
assert.step('activity_send_mail');
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (args.method === 'action_feedback_schedule_next'){
|
||||
assert.deepEqual([[3]],args.args, "Should execute action_feedback_schedule_next on activity 3 only ");
|
||||
assert.equal(args.kwargs.feedback, "feedback2");
|
||||
assert.step('action_feedback_schedule_next');
|
||||
return $.when({serverGeneratedAction: true});
|
||||
return Promise.resolve({serverGeneratedAction: true});
|
||||
}
|
||||
if (args.method === 'get_activity_data') {
|
||||
return $.when(ACTIVITY_DATA);
|
||||
return Promise.resolve(ACTIVITY_DATA);
|
||||
}
|
||||
return this._super(route, args);
|
||||
},
|
||||
@@ -305,12 +305,12 @@ QUnit.test('activity view: activity widget', function (assert) {
|
||||
assert.step("Unexpected action");
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
});
|
||||
var today = activity.$('table tbody tr:first td:nth-child(2).today');
|
||||
var dropdown = today.find('.dropdown-menu.o_activity');
|
||||
|
||||
testUtils.dom.click(today.find('.o_closest_deadline'));
|
||||
await testUtils.dom.click(today.find('.o_closest_deadline'));
|
||||
assert.hasClass(dropdown,'show', "dropdown should be displayed");
|
||||
assert.ok(dropdown.find('.o_activity_color_today:contains(Today)').length, "Title should be today");
|
||||
assert.ok(dropdown.find('.o_activity_title_entry[data-activity-id="2"]:first div:contains(template8)').length,
|
||||
@@ -318,20 +318,20 @@ QUnit.test('activity view: activity widget', function (assert) {
|
||||
assert.ok(dropdown.find('.o_activity_title_entry[data-activity-id="2"]:eq(1) div:contains(template9)').length,
|
||||
"template9 should be available");
|
||||
|
||||
testUtils.dom.click(dropdown.find('.o_activity_title_entry[data-activity-id="2"]:first .o_activity_template_preview'));
|
||||
testUtils.dom.click(dropdown.find('.o_activity_title_entry[data-activity-id="2"]:first .o_activity_template_send'));
|
||||
await testUtils.dom.click(dropdown.find('.o_activity_title_entry[data-activity-id="2"]:first .o_activity_template_preview'));
|
||||
await testUtils.dom.click(dropdown.find('.o_activity_title_entry[data-activity-id="2"]:first .o_activity_template_send'));
|
||||
var overdue = activity.$('table tbody tr:first td:nth-child(3).overdue');
|
||||
testUtils.dom.click(overdue.find('.o_closest_deadline'));
|
||||
await testUtils.dom.click(overdue.find('.o_closest_deadline'));
|
||||
dropdown = overdue.find('.dropdown-menu.o_activity');
|
||||
assert.notOk(dropdown.find('.o_activity_title div div div:first span').length,
|
||||
"No template should be available");
|
||||
|
||||
testUtils.dom.click(dropdown.find('.o_schedule_activity'));
|
||||
testUtils.dom.click(overdue.find('.o_closest_deadline'));
|
||||
testUtils.dom.click(dropdown.find('.o_mark_as_done'));
|
||||
await testUtils.dom.click(dropdown.find('.o_schedule_activity'));
|
||||
await testUtils.dom.click(overdue.find('.o_closest_deadline'));
|
||||
await testUtils.dom.click(dropdown.find('.o_mark_as_done'));
|
||||
dropdown.find('#activity_feedback').val("feedback2");
|
||||
|
||||
testUtils.dom.click(dropdown.find('.o_activity_popover_done_next'));
|
||||
await testUtils.dom.click(dropdown.find('.o_activity_popover_done_next'));
|
||||
assert.verifySteps([
|
||||
"do_action_compose",
|
||||
"activity_send_mail",
|
||||
@@ -342,10 +342,10 @@ QUnit.test('activity view: activity widget', function (assert) {
|
||||
|
||||
activity.destroy();
|
||||
});
|
||||
QUnit.test('activity view: no group_by_menu and no time_range_menu', function (assert) {
|
||||
QUnit.test('activity view: no group_by_menu and no time_range_menu', async function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
var actionManager = createActionManager({
|
||||
var actionManager = await createActionManager({
|
||||
actions: [{
|
||||
id: 1,
|
||||
name: 'Task Action',
|
||||
@@ -365,13 +365,13 @@ QUnit.test('activity view: no group_by_menu and no time_range_menu', function (a
|
||||
if (args.method === 'get_activity_data') {
|
||||
assert.deepEqual(args.kwargs.context, {lang: 'zz_ZZ'},
|
||||
'The context should have been passed');
|
||||
return $.when(ACTIVITY_DATA);
|
||||
return Promise.resolve(ACTIVITY_DATA);
|
||||
}
|
||||
return this._super(route, args);
|
||||
},
|
||||
});
|
||||
|
||||
actionManager.doAction(1);
|
||||
await actionManager.doAction(1);
|
||||
|
||||
assert.containsN(actionManager, '.o_search_options .o_dropdown button:visible', 2,
|
||||
"only two elements should be available in view search");
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,68 +20,64 @@ QUnit.module('Discuss in mobile', {
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test('mobile basic rendering', function (assert) {
|
||||
QUnit.test('mobile basic rendering', async function (assert) {
|
||||
// This is a very basic first test for the client action. However, with
|
||||
// the chat_service, it is hard to override RPCs (for instance, the
|
||||
// /mail/client_action route is always called when the test suite is
|
||||
// launched), and we must wait for this RPC to be done before starting to
|
||||
// test the interface. This should be refactored to facilitate the testing.
|
||||
assert.expect(16);
|
||||
var done = assert.async();
|
||||
|
||||
createDiscuss({
|
||||
var discuss = await createDiscuss({
|
||||
id: 1,
|
||||
context: {},
|
||||
params: {},
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
debug: true,
|
||||
}).then(function (discuss) {
|
||||
// test basic rendering in mobile
|
||||
assert.containsOnce(discuss, '.o_mail_discuss_content .o_mail_no_content',
|
||||
"should display the no content message");
|
||||
assert.containsOnce(discuss, '.o_mail_mobile_tabs',
|
||||
"should have rendered the tabs");
|
||||
assert.hasClass(discuss.$('.o_mail_mobile_tab[data-type=mailbox_inbox]'),'active',
|
||||
"should be in inbox tab");
|
||||
assert.containsOnce(discuss, '.o_mail_discuss_mobile_mailboxes_buttons:visible',
|
||||
"inbox/starred buttons should be visible");
|
||||
assert.hasClass(discuss.$('.o_mail_discuss_mobile_mailboxes_buttons .o_mailbox_inbox_item[data-type=mailbox_inbox]'),'btn-primary',
|
||||
"should be in inbox");
|
||||
assert.hasClass($('.o_mail_discuss_button_dm_chat'),'d-none',
|
||||
"should have invisible button 'New Message'");
|
||||
assert.hasClass($('.o_mail_discuss_button_multi_user_channel'),'d-none',
|
||||
"should have invisible button 'New Channel'");
|
||||
|
||||
// move to 'Chat' tab
|
||||
testUtils.dom.click(discuss.$('.o_mail_mobile_tab[data-type=dm_chat]'));
|
||||
assert.hasClass(discuss.$('.o_mail_mobile_tab[data-type=dm_chat]'),'active',
|
||||
"should be in 'Chat' tab");
|
||||
assert.containsNone(discuss, '.o_mail_discuss_content .o_mail_no_content',
|
||||
"should display the no content message");
|
||||
assert.strictEqual($('.o_mail_discuss_button_dm_chat').length, 1,
|
||||
"should have a button to open DM chat in 'Chat' tab");
|
||||
assert.doesNotHaveClass($('.o_mail_discuss_button_dm_chat'), 'd-none',
|
||||
"should be visible in 'Chat' tab");
|
||||
assert.hasClass($('.o_mail_discuss_button_multi_user_channel'),'d-none',
|
||||
"should have invisible button 'New Channel' in 'Chat' tab");
|
||||
testUtils.dom.click($('.o_mail_discuss_button_dm_chat'));
|
||||
assert.containsOnce(discuss, '.o_mail_add_thread input:visible',
|
||||
"should display the input to add a channel");
|
||||
|
||||
// move to 'Channels' tab
|
||||
testUtils.dom.click(discuss.$('.o_mail_mobile_tab[data-type=multi_user_channel]'));
|
||||
assert.hasClass($('.o_mail_discuss_button_dm_chat'),'d-none',
|
||||
"should have invisible button 'New Message' in 'Channels' tab");
|
||||
assert.doesNotHaveClass($('.o_mail_discuss_button_multi_user_channel'), 'd-none',
|
||||
"should have visible button 'New Channel' in 'Channels' tab");
|
||||
testUtils.dom.click($('.o_mail_discuss_button_multi_user_channel'));
|
||||
assert.containsOnce(discuss, '.o_mail_add_thread input:visible',
|
||||
"should display the input to add a channel");
|
||||
|
||||
discuss.destroy();
|
||||
done();
|
||||
});
|
||||
// test basic rendering in mobile
|
||||
assert.containsOnce(discuss, '.o_mail_discuss_content .o_mail_no_content',
|
||||
"should display the no content message");
|
||||
assert.containsOnce(discuss, '.o_mail_mobile_tabs',
|
||||
"should have rendered the tabs");
|
||||
assert.hasClass(discuss.$('.o_mail_mobile_tab[data-type=mailbox_inbox]'),'active',
|
||||
"should be in inbox tab");
|
||||
assert.containsOnce(discuss, '.o_mail_discuss_mobile_mailboxes_buttons:visible',
|
||||
"inbox/starred buttons should be visible");
|
||||
assert.hasClass(discuss.$('.o_mail_discuss_mobile_mailboxes_buttons .o_mailbox_inbox_item[data-type=mailbox_inbox]'),'btn-primary',
|
||||
"should be in inbox");
|
||||
assert.hasClass($('.o_mail_discuss_button_dm_chat'),'d-none',
|
||||
"should have invisible button 'New Message'");
|
||||
assert.hasClass($('.o_mail_discuss_button_multi_user_channel'),'d-none',
|
||||
"should have invisible button 'New Channel'");
|
||||
|
||||
// move to 'Chat' tab
|
||||
await testUtils.dom.click(discuss.$('.o_mail_mobile_tab[data-type=dm_chat]'));
|
||||
assert.hasClass(discuss.$('.o_mail_mobile_tab[data-type=dm_chat]'),'active',
|
||||
"should be in 'Chat' tab");
|
||||
assert.containsNone(discuss, '.o_mail_discuss_content .o_mail_no_content',
|
||||
"should display the no content message");
|
||||
assert.strictEqual($('.o_mail_discuss_button_dm_chat').length, 1,
|
||||
"should have a button to open DM chat in 'Chat' tab");
|
||||
assert.doesNotHaveClass($('.o_mail_discuss_button_dm_chat'), 'd-none',
|
||||
"should be visible in 'Chat' tab");
|
||||
assert.hasClass($('.o_mail_discuss_button_multi_user_channel'),'d-none',
|
||||
"should have invisible button 'New Channel' in 'Chat' tab");
|
||||
await testUtils.dom.click($('.o_mail_discuss_button_dm_chat'));
|
||||
assert.containsOnce(discuss, '.o_mail_add_thread input:visible',
|
||||
"should display the input to add a channel");
|
||||
|
||||
// move to 'Channels' tab
|
||||
await testUtils.dom.click(discuss.$('.o_mail_mobile_tab[data-type=multi_user_channel]'));
|
||||
assert.hasClass($('.o_mail_discuss_button_dm_chat'),'d-none',
|
||||
"should have invisible button 'New Message' in 'Channels' tab");
|
||||
assert.doesNotHaveClass($('.o_mail_discuss_button_multi_user_channel'), 'd-none',
|
||||
"should have visible button 'New Channel' in 'Channels' tab");
|
||||
await testUtils.dom.click($('.o_mail_discuss_button_multi_user_channel') );
|
||||
assert.containsOnce(discuss, '.o_mail_add_thread input:visible',
|
||||
"should display the input to add a channel");
|
||||
|
||||
discuss.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('on_{attach/detach}_callback', function (assert) {
|
||||
|
||||
@@ -145,7 +145,7 @@ QUnit.test('moderator: moderated channel with pending moderation message', funct
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
})
|
||||
.then(function (discuss) {
|
||||
.then(async function (discuss) {
|
||||
var $moderationBox = discuss.$(
|
||||
'.o_mail_discuss_item' +
|
||||
'[data-thread-id="mailbox_moderation"]');
|
||||
@@ -156,7 +156,7 @@ QUnit.test('moderator: moderated channel with pending moderation message', funct
|
||||
"the mailbox counter of the moderation mailbox should display '1'");
|
||||
|
||||
// 1. go to moderation mailbox
|
||||
testUtils.dom.click($moderationBox);
|
||||
await testUtils.dom.click($moderationBox);
|
||||
var $message = discuss.$('.o_thread_message');
|
||||
// check message
|
||||
assert.strictEqual($message.length, 1,
|
||||
@@ -210,7 +210,7 @@ QUnit.test('moderator: moderated channel with pending moderation message', funct
|
||||
'the moderate button "Discard" should be invisible by default');
|
||||
|
||||
// click on message moderation checkbox
|
||||
testUtils.dom.click($message.find('.moderation_checkbox'));
|
||||
await testUtils.dom.click($message.find('.moderation_checkbox'));
|
||||
assert.ok($message.find('.moderation_checkbox').prop('checked'),
|
||||
"the moderation checkbox should become checked after click");
|
||||
// check select all (disabled) / unselect all buttons (enabled)
|
||||
@@ -227,7 +227,7 @@ QUnit.test('moderator: moderated channel with pending moderation message', funct
|
||||
'the moderate button "Discard" should become visible');
|
||||
|
||||
// 2. go to channel 'general'
|
||||
testUtils.dom.click(discuss.$('.o_mail_discuss_item[data-thread-id="1"]'));
|
||||
await testUtils.dom.click(discuss.$('.o_mail_discuss_item[data-thread-id="1"]'));
|
||||
$message = discuss.$('.o_thread_message');
|
||||
// check correct message
|
||||
assert.strictEqual($message.length, 1,
|
||||
@@ -289,12 +289,12 @@ QUnit.test('moderator: accept pending moderation message', function (assert) {
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
})
|
||||
.then(function (discuss) {
|
||||
.then(async function (discuss) {
|
||||
// 1. go to moderation box
|
||||
var $moderationBox = discuss.$(
|
||||
'.o_mail_discuss_item' +
|
||||
'[data-thread-id="mailbox_moderation"]');
|
||||
testUtils.dom.click($moderationBox);
|
||||
await testUtils.dom.click($moderationBox);
|
||||
// check there is a message to moderate
|
||||
var $message = discuss.$('.o_thread_message');
|
||||
assert.strictEqual($message.length, 1,
|
||||
@@ -304,7 +304,7 @@ QUnit.test('moderator: accept pending moderation message', function (assert) {
|
||||
assert.strictEqual($message.find('.moderation_checkbox').length, 1,
|
||||
"the message should have a moderation checkbox");
|
||||
// accept the message pending moderation
|
||||
testUtils.dom.click(discuss.$('.o_thread_message_moderation[data-decision="accept"]'));
|
||||
await testUtils.dom.click(discuss.$('.o_thread_message_moderation[data-decision="accept"]'));
|
||||
assert.verifySteps(['moderate']);
|
||||
|
||||
// stop the fadeout animation and immediately remove the element
|
||||
@@ -313,7 +313,7 @@ QUnit.test('moderator: accept pending moderation message', function (assert) {
|
||||
"should now have no message displayed in moderation box");
|
||||
|
||||
// 2. go to channel 'general'
|
||||
testUtils.dom.click(discuss.$('.o_mail_discuss_item[data-thread-id="1"]'));
|
||||
await testUtils.dom.click(discuss.$('.o_mail_discuss_item[data-thread-id="1"]'));
|
||||
$message = discuss.$('.o_thread_message');
|
||||
// check message is there and has no moderate checkbox
|
||||
assert.strictEqual($message.length, 1,
|
||||
@@ -379,12 +379,12 @@ QUnit.test('moderator: reject pending moderation message (reject with explanatio
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
})
|
||||
.then(function (discuss) {
|
||||
.then(async function (discuss) {
|
||||
// 1. go to moderation box
|
||||
var $moderationBox = discuss.$(
|
||||
'.o_mail_discuss_item' +
|
||||
'[data-thread-id="mailbox_moderation"]');
|
||||
testUtils.dom.click($moderationBox);
|
||||
await testUtils.dom.click($moderationBox);
|
||||
// check there is a message to moderate
|
||||
var $message = discuss.$('.o_thread_message');
|
||||
assert.strictEqual($message.length, 1,
|
||||
@@ -394,7 +394,7 @@ QUnit.test('moderator: reject pending moderation message (reject with explanatio
|
||||
assert.strictEqual($message.find('.moderation_checkbox').length, 1,
|
||||
"the message should have a moderation checkbox");
|
||||
// reject the message pending moderation
|
||||
testUtils.dom.click(discuss.$('.o_thread_message_moderation[data-decision="reject"]'));
|
||||
await testUtils.dom.click(discuss.$('.o_thread_message_moderation[data-decision="reject"]'));
|
||||
|
||||
// check reject dialog prompt
|
||||
assert.strictEqual($('.modal-dialog').length, 1,
|
||||
@@ -419,7 +419,7 @@ QUnit.test('moderator: reject pending moderation message (reject with explanatio
|
||||
"should have a send button on the reject dialog");
|
||||
|
||||
// send mesage
|
||||
testUtils.dom.click($('.modal-footer button'));
|
||||
await testUtils.dom.click($('.modal-footer button'));
|
||||
assert.verifySteps(['moderate']);
|
||||
|
||||
// // stop the fadeout animation and immediately remove the element
|
||||
@@ -428,7 +428,7 @@ QUnit.test('moderator: reject pending moderation message (reject with explanatio
|
||||
"should now have no message displayed in moderation box");
|
||||
|
||||
// 2. go to channel 'general'
|
||||
testUtils.dom.click(discuss.$('.o_mail_discuss_item[data-thread-id="1"]'));
|
||||
await testUtils.dom.click(discuss.$('.o_mail_discuss_item[data-thread-id="1"]'));
|
||||
assert.containsNone(discuss, '.o_thread_message')
|
||||
|
||||
discuss.destroy();
|
||||
@@ -482,12 +482,12 @@ QUnit.test('moderator: discard pending moderation message (reject without explan
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
})
|
||||
.then(function (discuss) {
|
||||
.then(async function (discuss) {
|
||||
// 1. go to moderation box
|
||||
var $moderationBox = discuss.$(
|
||||
'.o_mail_discuss_item' +
|
||||
'[data-thread-id="mailbox_moderation"]');
|
||||
testUtils.dom.click($moderationBox);
|
||||
await testUtils.dom.click($moderationBox);
|
||||
// check there is a message to moderate
|
||||
var $message = discuss.$('.o_thread_message');
|
||||
assert.strictEqual($message.length, 1,
|
||||
@@ -497,7 +497,7 @@ QUnit.test('moderator: discard pending moderation message (reject without explan
|
||||
assert.strictEqual($message.find('.moderation_checkbox').length, 1,
|
||||
"the message should have a moderation checkbox");
|
||||
// discard the message pending moderation
|
||||
testUtils.dom.click(discuss.$('.o_thread_message_moderation[data-decision="discard"]'));
|
||||
await testUtils.dom.click(discuss.$('.o_thread_message_moderation[data-decision="discard"]'));
|
||||
|
||||
// check discard dialog prompt
|
||||
assert.strictEqual($('.modal-dialog').length, 1,
|
||||
@@ -513,7 +513,7 @@ QUnit.test('moderator: discard pending moderation message (reject without explan
|
||||
"should have a cancel button in the dialog for discard");
|
||||
|
||||
// discard mesage
|
||||
testUtils.dom.click($('.modal-footer button.btn-primary'));
|
||||
await testUtils.dom.click($('.modal-footer button.btn-primary'));
|
||||
assert.verifySteps(['moderate']);
|
||||
|
||||
// stop the fadeout animation and immediately remove the element
|
||||
@@ -522,7 +522,7 @@ QUnit.test('moderator: discard pending moderation message (reject without explan
|
||||
"should now have no message displayed in moderation box");
|
||||
|
||||
// 2. go to channel 'general'
|
||||
testUtils.dom.click(discuss.$('.o_mail_discuss_item[data-thread-id="1"]'));
|
||||
await testUtils.dom.click(discuss.$('.o_mail_discuss_item[data-thread-id="1"]'));
|
||||
assert.containsNone(discuss, '.o_thread_message')
|
||||
|
||||
discuss.destroy();
|
||||
@@ -534,7 +534,7 @@ QUnit.test('author: send message in moderated channel', function (assert) {
|
||||
assert.expect(4);
|
||||
var done = assert.async();
|
||||
|
||||
var messagePostDef = $.Deferred();
|
||||
var messagePostDef = testUtils.makeTestPromise();
|
||||
|
||||
this.data.initMessaging = {
|
||||
channel_slots: {
|
||||
@@ -554,7 +554,7 @@ QUnit.test('author: send message in moderated channel', function (assert) {
|
||||
params: {},
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
mockRPC: function (route, args) {
|
||||
mockRPC: async function (route, args) {
|
||||
if (args.method === 'message_post') {
|
||||
var message = {
|
||||
id: 100,
|
||||
@@ -572,9 +572,10 @@ QUnit.test('author: send message in moderated channel', function (assert) {
|
||||
};
|
||||
var notification = [metaData, notifData];
|
||||
objectDiscuss.call('bus_service', 'trigger', 'notification', [notification]);
|
||||
await testUtils.nextTick();
|
||||
|
||||
messagePostDef.resolve();
|
||||
return $.when(message.id);
|
||||
return Promise.resolve(message.id);
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
@@ -582,14 +583,14 @@ QUnit.test('author: send message in moderated channel', function (assert) {
|
||||
partner_id: 2,
|
||||
},
|
||||
})
|
||||
.then(function (discuss) {
|
||||
.then(async function (discuss) {
|
||||
objectDiscuss = discuss;
|
||||
|
||||
// go to channel 'general'
|
||||
testUtils.dom.click(discuss.$('.o_mail_discuss_item[data-thread-id="1"]'));
|
||||
await testUtils.dom.click(discuss.$('.o_mail_discuss_item[data-thread-id="1"]'));
|
||||
// post a message
|
||||
discuss.$('.o_composer_input textarea').first().val("some text");
|
||||
testUtils.dom.click(discuss.$('.o_composer_send button'));
|
||||
await testUtils.dom.click(discuss.$('.o_composer_send button'));
|
||||
|
||||
messagePostDef
|
||||
.then(function () {
|
||||
@@ -646,10 +647,10 @@ QUnit.test('author: sent message accepted in moderated channel', function (asser
|
||||
partner_id: 2,
|
||||
},
|
||||
})
|
||||
.then(function (discuss) {
|
||||
.then(async function (discuss) {
|
||||
|
||||
// go to channel 'general'
|
||||
testUtils.dom.click(discuss.$('.o_mail_discuss_item[data-thread-id="1"]'));
|
||||
await testUtils.dom.click(discuss.$('.o_mail_discuss_item[data-thread-id="1"]'));
|
||||
// check message is pending
|
||||
var $message = discuss.$('.o_thread_message');
|
||||
assert.strictEqual($message.length, 1,
|
||||
@@ -674,7 +675,7 @@ QUnit.test('author: sent message accepted in moderated channel', function (asser
|
||||
var metaData = [dbName, 'mail.channel'];
|
||||
var notification = [metaData, messageData];
|
||||
discuss.call('bus_service', 'trigger', 'notification', [notification]);
|
||||
|
||||
await testUtils.nextTick();
|
||||
// check message is accepted
|
||||
$message = discuss.$('.o_thread_message');
|
||||
assert.strictEqual($message.length, 1,
|
||||
@@ -727,10 +728,10 @@ QUnit.test('author: sent message rejected in moderated channel', function (asser
|
||||
partner_id: 2,
|
||||
},
|
||||
})
|
||||
.then(function (discuss) {
|
||||
.then(async function (discuss) {
|
||||
|
||||
// go to channel 'general'
|
||||
testUtils.dom.click(discuss.$('.o_mail_discuss_item[data-thread-id="1"]'));
|
||||
await testUtils.dom.click(discuss.$('.o_mail_discuss_item[data-thread-id="1"]'));
|
||||
// check message is pending
|
||||
var $message = discuss.$('.o_thread_message');
|
||||
assert.strictEqual($message.length, 1,
|
||||
@@ -751,7 +752,7 @@ QUnit.test('author: sent message rejected in moderated channel', function (asser
|
||||
var metaData = [dbName, 'res.partner'];
|
||||
var notification = [metaData, notifData];
|
||||
discuss.call('bus_service', 'trigger', 'notification', [notification]);
|
||||
|
||||
await testUtils.nextTick();
|
||||
// // check no message
|
||||
assert.containsNone(discuss, '.o_thread_message',
|
||||
"message should be removed from channel after reject");
|
||||
@@ -761,12 +762,11 @@ QUnit.test('author: sent message rejected in moderated channel', function (asser
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test('no crash when load-more fetching "accepted" message twice', function (assert) {
|
||||
QUnit.test('no crash when load-more fetching "accepted" message twice', async 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;
|
||||
@@ -799,7 +799,7 @@ QUnit.test('no crash when load-more fetching "accepted" message twice', function
|
||||
};
|
||||
var count = 0;
|
||||
|
||||
createDiscuss({
|
||||
var discuss = await createDiscuss({
|
||||
id: 1,
|
||||
context: {},
|
||||
params: {},
|
||||
@@ -811,33 +811,32 @@ QUnit.test('no crash when load-more fetching "accepted" message twice', function
|
||||
count++;
|
||||
if (count === 1) {
|
||||
// inbox message_fetch
|
||||
return $.when([]);
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
// general message_fetch
|
||||
return $.when(messageData);
|
||||
return Promise.resolve(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();
|
||||
});
|
||||
|
||||
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
|
||||
await testUtils.dom.click($general);
|
||||
|
||||
// simulate search
|
||||
discuss.trigger_up('search', {
|
||||
domains: [['author_id', '=', 100]],
|
||||
});
|
||||
await testUtils.nextTick();
|
||||
|
||||
discuss.destroy();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -153,15 +153,14 @@ QUnit.module('Discuss (Typing Notifications)', {
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test('notify is typing', function (assert) {
|
||||
QUnit.test('notify is typing', async function (assert) {
|
||||
assert.expect(11);
|
||||
var done = assert.async();
|
||||
|
||||
// this is to track the step that we are testing in the `notify_typing`
|
||||
// mocked RPC
|
||||
var step = 1;
|
||||
|
||||
createDiscuss({
|
||||
var discuss = await createDiscuss({
|
||||
id: 1,
|
||||
context: {},
|
||||
params: {},
|
||||
@@ -188,44 +187,42 @@ QUnit.test('notify is typing', function (assert) {
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
session: { partner_id: this.myPartnerID },
|
||||
}).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.hasAttrValue($general, 'title', 'general',
|
||||
"should have the title 'general'");
|
||||
|
||||
// click on general
|
||||
testUtils.dom.click($general);
|
||||
|
||||
var $input = discuss.$('textarea.o_composer_text_field').first();
|
||||
assert.ok($input.length, "should display a composer input");
|
||||
|
||||
// STEP 1: current user is typing something
|
||||
step = 1;
|
||||
$input.focus();
|
||||
testUtils.fields.editInput($input, '1');
|
||||
|
||||
assert.verifySteps(['notify_typing']);
|
||||
|
||||
// STEP 2: current user clears input
|
||||
step = 2;
|
||||
testUtils.fields.editInput($input, '');
|
||||
|
||||
assert.verifySteps(['notify_typing', 'notify_typing']);
|
||||
|
||||
discuss.destroy();
|
||||
done();
|
||||
});
|
||||
|
||||
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.hasAttrValue($general, 'title', 'general',
|
||||
"should have the title 'general'");
|
||||
|
||||
// click on general
|
||||
await testUtils.dom.click($general);
|
||||
|
||||
var $input = discuss.$('textarea.o_composer_text_field').first();
|
||||
assert.ok($input.length, "should display a composer input");
|
||||
|
||||
// STEP 1: current user is typing something
|
||||
step = 1;
|
||||
$input.focus();
|
||||
testUtils.fields.editInput($input, '1');
|
||||
|
||||
assert.verifySteps(['notify_typing']);
|
||||
|
||||
// STEP 2: current user clears input
|
||||
step = 2;
|
||||
testUtils.fields.editInput($input, '');
|
||||
|
||||
assert.verifySteps(['notify_typing']);
|
||||
|
||||
discuss.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('receive is typing notification', function (assert) {
|
||||
QUnit.test('receive is typing notification', async function (assert) {
|
||||
assert.expect(10);
|
||||
|
||||
var self = this;
|
||||
createDiscuss({
|
||||
var discuss = await createDiscuss({
|
||||
id: 1,
|
||||
context: {},
|
||||
params: {},
|
||||
@@ -235,7 +232,7 @@ QUnit.test('receive is typing notification', function (assert) {
|
||||
// when receiving an 'is typing' notification, fetch the list of
|
||||
// members of this channel if we haven't done yet.
|
||||
if (args.method === 'channel_fetch_listeners') {
|
||||
return $.when([
|
||||
return Promise.resolve([
|
||||
{ id: self.myPartnerID, name: self.myName },
|
||||
{ id: 42, name: "Someone" },
|
||||
]);
|
||||
@@ -243,67 +240,68 @@ QUnit.test('receive is typing notification', function (assert) {
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
session: { partner_id: this.myPartnerID },
|
||||
}).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.hasAttrValue($general, 'title', 'general',
|
||||
"should have the title 'general'");
|
||||
|
||||
// pick 1st composer (basic), not 2nd composer (extended, hidden)
|
||||
var $composer = discuss.$('.o_thread_composer').first();
|
||||
|
||||
// click on general
|
||||
testUtils.dom.click($general);
|
||||
assert.containsNone($general, '.o_mail_thread_typing_icon',
|
||||
"should no longer show someone is typing in sidebar of discuss");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(), "",
|
||||
"should no longer show someone is typing on the composer of active thread");
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: 42,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.containsOnce($general, '.o_mail_thread_typing_icon',
|
||||
"should have a thread typing icon next to general icon in the sidebar");
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"Someone is typing...",
|
||||
"should show who is typing on hover on this thread typing icon");
|
||||
assert.containsOnce($composer, '.o_composer_thread_typing',
|
||||
"should show typing info on the composer of active thread");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"Someone is typing...",
|
||||
"should show who is typing on the composer of active thread");
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: false,
|
||||
partnerID: 42,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.containsNone($general, '.o_mail_thread_typing_icon',
|
||||
"should no longer show someone is typing in sidebar of discuss");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(), "",
|
||||
"should no longer show someone is typing on the composer of active thread");
|
||||
|
||||
discuss.destroy();
|
||||
});
|
||||
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.hasAttrValue($general, 'title', 'general',
|
||||
"should have the title 'general'");
|
||||
|
||||
// pick 1st composer (basic), not 2nd composer (extended, hidden)
|
||||
var $composer = discuss.$('.o_thread_composer').first();
|
||||
|
||||
// click on general
|
||||
await testUtils.dom.click($general);
|
||||
assert.containsNone($general, '.o_mail_thread_typing_icon',
|
||||
"should no longer show someone is typing in sidebar of discuss");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(), "",
|
||||
"should no longer show someone is typing on the composer of active thread");
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: 42,
|
||||
widget: discuss,
|
||||
});
|
||||
await testUtils.nextMicrotaskTick();
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.containsOnce($general, '.o_mail_thread_typing_icon',
|
||||
"should have a thread typing icon next to general icon in the sidebar");
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"Someone is typing...",
|
||||
"should show who is typing on hover on this thread typing icon");
|
||||
assert.containsOnce($composer, '.o_composer_thread_typing',
|
||||
"should show typing info on the composer of active thread");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"Someone is typing...",
|
||||
"should show who is typing on the composer of active thread");
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: false,
|
||||
partnerID: 42,
|
||||
widget: discuss,
|
||||
});
|
||||
await testUtils.nextMicrotaskTick();
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.containsNone($general, '.o_mail_thread_typing_icon',
|
||||
"should no longer show someone is typing in sidebar of discuss");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(), "",
|
||||
"should no longer show someone is typing on the composer of active thread");
|
||||
|
||||
discuss.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('receive message of someone that was typing something', function (assert) {
|
||||
QUnit.test('receive message of someone that was typing something', async function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
var self = this;
|
||||
createDiscuss({
|
||||
var discuss = await createDiscuss({
|
||||
id: 1,
|
||||
context: {},
|
||||
params: {},
|
||||
@@ -313,7 +311,7 @@ QUnit.test('receive message of someone that was typing something', function (ass
|
||||
// when receiving an 'is typing' notification, fetch the list of
|
||||
// members of this channel if we haven't done yet.
|
||||
if (args.method === 'channel_fetch_listeners') {
|
||||
return $.when([
|
||||
return Promise.resolve([
|
||||
{ id: self.myPartnerID, name: self.myName },
|
||||
{ id: 42, name: "Someone" },
|
||||
]);
|
||||
@@ -321,62 +319,63 @@ QUnit.test('receive message of someone that was typing something', function (ass
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
session: { partner_id: this.myPartnerID },
|
||||
}).then(function (discuss) {
|
||||
// click on general channel
|
||||
var $general = discuss.$('.o_mail_discuss_sidebar .o_mail_discuss_item[data-thread-id=1]');
|
||||
testUtils.dom.click($general);
|
||||
|
||||
// pick 1st composer (basic), not 2nd composer (extended, hidden)
|
||||
var $composer = discuss.$('.o_thread_composer').first();
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: 42,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.containsOnce($general, '.o_mail_thread_typing_icon',
|
||||
"should have a thread typing icon next to general icon in the sidebar");
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"Someone is typing...",
|
||||
"should show who is typing on hover on this thread typing icon");
|
||||
assert.containsOnce($composer, '.o_composer_thread_typing',
|
||||
"should show typing info on the composer of active thread");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"Someone is typing...",
|
||||
"should show who is typing on the composer of active thread");
|
||||
|
||||
// Simulate receive message from the person typing something
|
||||
var messageData = {
|
||||
author_id: [42, 'Someone'],
|
||||
body: "<p>test</p>",
|
||||
channel_ids: [1],
|
||||
id: 101,
|
||||
model: 'mail.channel',
|
||||
res_id: 1,
|
||||
};
|
||||
var notification = [[false, 'mail.channel', 1], messageData];
|
||||
discuss.call('bus_service', 'trigger', 'notification', [notification]);
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.containsNone($general, '.o_mail_thread_typing_icon',
|
||||
"should no longer show someone is typing in sidebar of discuss, after receiving message");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(), "",
|
||||
"should no longer show someone is typing on the composer of active thread, after receiving message");
|
||||
|
||||
discuss.destroy();
|
||||
});
|
||||
// click on general channel
|
||||
var $general = discuss.$('.o_mail_discuss_sidebar .o_mail_discuss_item[data-thread-id=1]');
|
||||
await testUtils.dom.click($general);
|
||||
|
||||
// pick 1st composer (basic), not 2nd composer (extended, hidden)
|
||||
var $composer = discuss.$('.o_thread_composer').first();
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: 42,
|
||||
widget: discuss,
|
||||
});
|
||||
await testUtils.nextMicrotaskTick();
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.containsOnce($general, '.o_mail_thread_typing_icon',
|
||||
"should have a thread typing icon next to general icon in the sidebar");
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"Someone is typing...",
|
||||
"should show who is typing on hover on this thread typing icon");
|
||||
assert.containsOnce($composer, '.o_composer_thread_typing',
|
||||
"should show typing info on the composer of active thread");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"Someone is typing...",
|
||||
"should show who is typing on the composer of active thread");
|
||||
|
||||
// Simulate receive message from the person typing something
|
||||
var messageData = {
|
||||
author_id: [42, 'Someone'],
|
||||
body: "<p>test</p>",
|
||||
channel_ids: [1],
|
||||
id: 101,
|
||||
model: 'mail.channel',
|
||||
res_id: 1,
|
||||
};
|
||||
var notification = [[false, 'mail.channel', 1], messageData];
|
||||
await discuss.call('bus_service', 'trigger', 'notification', [notification]);
|
||||
await testUtils.nextTick();
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.containsNone($general, '.o_mail_thread_typing_icon',
|
||||
"should no longer show someone is typing in sidebar of discuss, after receiving message");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(), "",
|
||||
"should no longer show someone is typing on the composer of active thread, after receiving message");
|
||||
|
||||
discuss.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('do not display myself as typing', function (assert) {
|
||||
QUnit.test('do not display myself as typing', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
var self = this;
|
||||
createDiscuss({
|
||||
var discuss = await createDiscuss({
|
||||
id: 1,
|
||||
context: {},
|
||||
params: {},
|
||||
@@ -386,40 +385,39 @@ QUnit.test('do not display myself as typing', function (assert) {
|
||||
// when receiving an 'is typing' notification, fetch the list of
|
||||
// members of this channel if we haven't done yet.
|
||||
if (args.method === 'channel_fetch_listeners') {
|
||||
return $.when([
|
||||
return Promise.resolve([
|
||||
{ id: self.myPartnerID, name: self.myName },
|
||||
]);
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
session: { partner_id: this.myPartnerID },
|
||||
}).then(function (discuss) {
|
||||
// click on general channel
|
||||
var $general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
testUtils.dom.click($general);
|
||||
// pick 1st composer (basic), not 2nd composer (extended, hidden)
|
||||
var $composer = discuss.$('.o_thread_composer').first();
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: self.myPartnerID,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.containsNone($general, '.o_mail_thread_typing_icon',
|
||||
"should not show current user is typing in sidebar of discuss");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(), "",
|
||||
"should not show current user is typing on the composer of active thread");
|
||||
|
||||
discuss.destroy();
|
||||
});
|
||||
// click on general channel
|
||||
var $general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
await testUtils.dom.click($general);
|
||||
// pick 1st composer (basic), not 2nd composer (extended, hidden)
|
||||
var $composer = discuss.$('.o_thread_composer').first();
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: self.myPartnerID,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.containsNone($general, '.o_mail_thread_typing_icon',
|
||||
"should not show current user is typing in sidebar of discuss");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(), "",
|
||||
"should not show current user is typing on the composer of active thread");
|
||||
|
||||
discuss.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('several users typing something at the same time', function (assert) {
|
||||
QUnit.test('several users typing something at the same time', async function (assert) {
|
||||
// The order to display several typing partners name is not random:
|
||||
// it shows at most 2 typing partners, which are the typing partners that
|
||||
// have been typing something for the longest time.
|
||||
@@ -428,7 +426,7 @@ QUnit.test('several users typing something at the same time', function (assert)
|
||||
assert.expect(10);
|
||||
|
||||
var self = this;
|
||||
createDiscuss({
|
||||
var discuss = await createDiscuss({
|
||||
id: 1,
|
||||
context: {},
|
||||
params: {},
|
||||
@@ -438,7 +436,7 @@ QUnit.test('several users typing something at the same time', function (assert)
|
||||
// when receiving an 'is typing' notification, fetch the list of
|
||||
// members of this channel if we haven't done yet.
|
||||
if (args.method === 'channel_fetch_listeners') {
|
||||
return $.when([
|
||||
return Promise.resolve([
|
||||
{ id: self.myPartnerID, name: self.myName },
|
||||
{ id: 42, name: "Someone" },
|
||||
{ id: 43, name: "Anonymous" },
|
||||
@@ -448,98 +446,101 @@ QUnit.test('several users typing something at the same time', function (assert)
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
session: { partner_id: this.myPartnerID },
|
||||
}).then(function (discuss) {
|
||||
// click on general channel
|
||||
var $general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
|
||||
// click on general
|
||||
testUtils.dom.click($general);
|
||||
|
||||
// pick 1st composer (basic), not 2nd composer (extended, hidden)
|
||||
var $composer = discuss.$('.o_thread_composer').first();
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: 42,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.containsOnce($general, '.o_mail_thread_typing_icon',
|
||||
"should have a thread typing icon next to general icon in the sidebar");
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"Someone is typing...",
|
||||
"should show someone is typing on hover on this thread typing icon");
|
||||
assert.containsOnce($composer, '.o_composer_thread_typing',
|
||||
"should show typing info on the composer of active thread");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"Someone is typing...",
|
||||
"should show someone is typing on the composer of active thread");
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: 43,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"Someone and Anonymous are typing...",
|
||||
"should show someone and anonymous are simultaneously typing on hover on this thread typing icon");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"Someone and Anonymous are typing...",
|
||||
"should show someone and anonymous are simultaneously typing on the composer of active thread");
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: 44,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"Someone, Anonymous and more are typing...",
|
||||
"should show 2 and more users are simultaneously typing on hover on this thread typing icon");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"Someone, Anonymous and more are typing...",
|
||||
"should show 2 and more users are simultaneously typing on the composer of active thread");
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: false,
|
||||
partnerID: 42,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"Anonymous and Shy Guy are typing...",
|
||||
"should no longer show than someone is typing on hover on this thread typing icon");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"Anonymous and Shy Guy are typing...",
|
||||
"should no longer show than someone is typing on the composer of active thread");
|
||||
|
||||
discuss.destroy();
|
||||
});
|
||||
// click on general channel
|
||||
var $general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
|
||||
// click on general
|
||||
await testUtils.dom.click($general);
|
||||
|
||||
// pick 1st composer (basic), not 2nd composer (extended, hidden)
|
||||
var $composer = discuss.$('.o_thread_composer').first();
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: 42,
|
||||
widget: discuss,
|
||||
});
|
||||
await testUtils.nextMicrotaskTick();
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.containsOnce($general, '.o_mail_thread_typing_icon',
|
||||
"should have a thread typing icon next to general icon in the sidebar");
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"Someone is typing...",
|
||||
"should show someone is typing on hover on this thread typing icon");
|
||||
assert.containsOnce($composer, '.o_composer_thread_typing',
|
||||
"should show typing info on the composer of active thread");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"Someone is typing...",
|
||||
"should show someone is typing on the composer of active thread");
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: 43,
|
||||
widget: discuss,
|
||||
});
|
||||
await testUtils.nextMicrotaskTick();
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"Someone and Anonymous are typing...",
|
||||
"should show someone and anonymous are simultaneously typing on hover on this thread typing icon");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"Someone and Anonymous are typing...",
|
||||
"should show someone and anonymous are simultaneously typing on the composer of active thread");
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: 44,
|
||||
widget: discuss,
|
||||
});
|
||||
await testUtils.nextMicrotaskTick();
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"Someone, Anonymous and more are typing...",
|
||||
"should show 2 and more users are simultaneously typing on hover on this thread typing icon");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"Someone, Anonymous and more are typing...",
|
||||
"should show 2 and more users are simultaneously typing on the composer of active thread");
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: false,
|
||||
partnerID: 42,
|
||||
widget: discuss,
|
||||
});
|
||||
await testUtils.nextMicrotaskTick();
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"Anonymous and Shy Guy are typing...",
|
||||
"should no longer show than someone is typing on hover on this thread typing icon");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"Anonymous and Shy Guy are typing...",
|
||||
"should no longer show than someone is typing on the composer of active thread");
|
||||
|
||||
discuss.destroy();
|
||||
});
|
||||
|
||||
|
||||
QUnit.test('long typing partner A and in-between short typing partner B', function (assert) {
|
||||
QUnit.test('long typing partner A and in-between short typing partner B', async function (assert) {
|
||||
// Let's suppose that A is typing a very long message. If B types a short
|
||||
// and sends it, it should display that B is typing, remove B from display
|
||||
// when receiving the message, but still keep A in the typing notification.
|
||||
assert.expect(8);
|
||||
|
||||
var self = this;
|
||||
createDiscuss({
|
||||
var discuss = await createDiscuss({
|
||||
id: 1,
|
||||
context: {},
|
||||
params: {},
|
||||
@@ -549,7 +550,7 @@ QUnit.test('long typing partner A and in-between short typing partner B', functi
|
||||
// when receiving an 'is typing' notification, fetch the list of
|
||||
// members of this channel if we haven't done yet.
|
||||
if (args.method === 'channel_fetch_listeners') {
|
||||
return $.when([
|
||||
return Promise.resolve([
|
||||
{ id: self.myPartnerID, name: self.myName },
|
||||
{ id: 42, name: "A" },
|
||||
{ id: 43, name: "B" },
|
||||
@@ -558,76 +559,78 @@ QUnit.test('long typing partner A and in-between short typing partner B', functi
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
session: { partner_id: this.myPartnerID },
|
||||
}).then(function (discuss) {
|
||||
// click on general channel
|
||||
var $general = discuss.$('.o_mail_discuss_sidebar .o_mail_discuss_item[data-thread-id=1]');
|
||||
testUtils.dom.click($general);
|
||||
// pick 1st composer (basic), not 2nd composer (extended, hidden)
|
||||
var $composer = discuss.$('.o_thread_composer').first();
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: 42,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.containsOnce($general, '.o_mail_thread_typing_icon',
|
||||
"should have a thread typing icon next to general icon in the sidebar");
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"A is typing...",
|
||||
"should show A is typing on hover on this thread typing icon");
|
||||
assert.containsOnce($composer, '.o_composer_thread_typing',
|
||||
"should show typing info on the composer of active thread");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"A is typing...",
|
||||
"should show A is typing on the composer of active thread");
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: 43,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
// B comes after A in the display, because A is oldest typing partner.
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"A and B are typing...",
|
||||
"should show A and B are typing on hover on this thread typing icon");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"A and B are typing...",
|
||||
"should show A and B are typing on the composer of active thread");
|
||||
|
||||
// Simulate receive message from B
|
||||
var messageData = {
|
||||
author_id: [43, 'Someone'],
|
||||
body: "<p>test</p>",
|
||||
channel_ids: [1],
|
||||
id: 101,
|
||||
model: 'mail.channel',
|
||||
res_id: 1,
|
||||
};
|
||||
var notification = [[false, 'mail.channel', 1], messageData];
|
||||
discuss.call('bus_service', 'trigger', 'notification', [notification]);
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"A is typing...",
|
||||
"should show A is still typing on hover on this thread typing icon");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"A is typing...",
|
||||
"should show A is still typing on the composer of active thread");
|
||||
|
||||
discuss.destroy();
|
||||
});
|
||||
// click on general channel
|
||||
var $general = discuss.$('.o_mail_discuss_sidebar .o_mail_discuss_item[data-thread-id=1]');
|
||||
await testUtils.dom.click($general);
|
||||
// pick 1st composer (basic), not 2nd composer (extended, hidden)
|
||||
var $composer = discuss.$('.o_thread_composer').first();
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: 42,
|
||||
widget: discuss,
|
||||
});
|
||||
await testUtils.nextMicrotaskTick();
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.containsOnce($general, '.o_mail_thread_typing_icon',
|
||||
"should have a thread typing icon next to general icon in the sidebar");
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"A is typing...",
|
||||
"should show A is typing on hover on this thread typing icon");
|
||||
assert.containsOnce($composer, '.o_composer_thread_typing',
|
||||
"should show typing info on the composer of active thread");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"A is typing...",
|
||||
"should show A is typing on the composer of active thread");
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: 43,
|
||||
widget: discuss,
|
||||
});
|
||||
await testUtils.nextMicrotaskTick();
|
||||
|
||||
// B comes after A in the display, because A is oldest typing partner.
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"A and B are typing...",
|
||||
"should show A and B are typing on hover on this thread typing icon");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"A and B are typing...",
|
||||
"should show A and B are typing on the composer of active thread");
|
||||
|
||||
// Simulate receive message from B
|
||||
var messageData = {
|
||||
author_id: [43, 'Someone'],
|
||||
body: "<p>test</p>",
|
||||
channel_ids: [1],
|
||||
id: 101,
|
||||
model: 'mail.channel',
|
||||
res_id: 1,
|
||||
};
|
||||
var notification = [[false, 'mail.channel', 1], messageData];
|
||||
await discuss.call('bus_service', 'trigger', 'notification', [notification]);
|
||||
await testUtils.nextTick();
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"A is typing...",
|
||||
"should show A is still typing on hover on this thread typing icon");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"A is typing...",
|
||||
"should show A is still typing on the composer of active thread");
|
||||
|
||||
discuss.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('receive is typing notification from unselected thread', function (assert) {
|
||||
QUnit.test('receive is typing notification from unselected thread', async function (assert) {
|
||||
assert.expect(7);
|
||||
|
||||
this.data.initMessaging.channel_slots.channel_channel.push({
|
||||
@@ -637,7 +640,7 @@ QUnit.test('receive is typing notification from unselected thread', function (as
|
||||
});
|
||||
|
||||
var self = this;
|
||||
createDiscuss({
|
||||
var discuss = await createDiscuss({
|
||||
id: 1,
|
||||
context: {},
|
||||
params: {},
|
||||
@@ -647,7 +650,7 @@ QUnit.test('receive is typing notification from unselected thread', function (as
|
||||
// when receiving an 'is typing' notification, fetch the list of
|
||||
// members of this channel if we haven't done yet.
|
||||
if (args.method === 'channel_fetch_listeners') {
|
||||
return $.when([
|
||||
return Promise.resolve([
|
||||
{ id: self.myPartnerID, name: self.myName },
|
||||
{ id: 42, name: "Someone" },
|
||||
]);
|
||||
@@ -655,44 +658,44 @@ QUnit.test('receive is typing notification from unselected thread', function (as
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
session: { partner_id: this.myPartnerID },
|
||||
}).then(function (discuss) {
|
||||
var $general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
var $other = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=2]');
|
||||
assert.strictEqual($general.length, 1,
|
||||
"should have the channel item with id 1");
|
||||
assert.hasAttrValue($general, 'title', 'general',
|
||||
"should have the title 'general'");
|
||||
assert.strictEqual($other.length, 1,
|
||||
"should have the channel item with id 2");
|
||||
assert.hasAttrValue($other, 'title', 'other',
|
||||
"should have the title 'other'");
|
||||
|
||||
// click on general
|
||||
testUtils.dom.click($general);
|
||||
|
||||
assert.containsNone($general, '.o_mail_thread_typing_icon',
|
||||
"should no longer show someone is typing in sidebar of discuss");
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 2,
|
||||
isTyping: true,
|
||||
partnerID: 42,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
$other = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=2]');
|
||||
assert.containsNone($general, '.o_mail_thread_typing_icon',
|
||||
"should not have a thread typing icon next to general icon in the sidebar");
|
||||
assert.containsOnce($other, '.o_mail_thread_typing_icon',
|
||||
"should have a thread typing icon next to other icon in the sidebar");
|
||||
|
||||
discuss.destroy();
|
||||
});
|
||||
var $general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
var $other = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=2]');
|
||||
assert.strictEqual($general.length, 1,
|
||||
"should have the channel item with id 1");
|
||||
assert.hasAttrValue($general, 'title', 'general',
|
||||
"should have the title 'general'");
|
||||
assert.strictEqual($other.length, 1,
|
||||
"should have the channel item with id 2");
|
||||
assert.hasAttrValue($other, 'title', 'other',
|
||||
"should have the title 'other'");
|
||||
|
||||
// click on general
|
||||
await testUtils.dom.click($general);
|
||||
|
||||
assert.containsNone($general, '.o_mail_thread_typing_icon',
|
||||
"should no longer show someone is typing in sidebar of discuss");
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 2,
|
||||
isTyping: true,
|
||||
partnerID: 42,
|
||||
widget: discuss,
|
||||
});
|
||||
await testUtils.nextMicrotaskTick();
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
$other = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=2]');
|
||||
assert.containsNone($general, '.o_mail_thread_typing_icon',
|
||||
"should not have a thread typing icon next to general icon in the sidebar");
|
||||
assert.containsOnce($other, '.o_mail_thread_typing_icon',
|
||||
"should have a thread typing icon next to other icon in the sidebar");
|
||||
|
||||
discuss.destroy();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -87,7 +87,7 @@ QUnit.module('Document Thread', {
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test('open a document thread in a thread window', function (assert) {
|
||||
QUnit.test('open a document thread in a thread window', async function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
var messagingMenu = new MessagingMenu();
|
||||
@@ -107,13 +107,13 @@ QUnit.test('open a document thread in a thread window', function (assert) {
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
|
||||
// toggle the messaging menu and open the documentThread
|
||||
testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
await testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
assert.containsOnce(messagingMenu, '.o_mail_preview',
|
||||
"should display one preview");
|
||||
testUtils.dom.click(messagingMenu.$('.o_mail_preview'));
|
||||
await testUtils.dom.click(messagingMenu.$('.o_mail_preview'));
|
||||
|
||||
assert.strictEqual($('.o_thread_window').length, 1,
|
||||
"should have open the DocumentThread in a thread window");
|
||||
@@ -125,7 +125,7 @@ QUnit.test('open a document thread in a thread window', function (assert) {
|
||||
messagingMenu.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('expand a document thread window', function (assert) {
|
||||
QUnit.test('expand a document thread window', async function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
var messagingMenu = new MessagingMenu();
|
||||
@@ -144,13 +144,13 @@ QUnit.test('expand a document thread window', function (assert) {
|
||||
},
|
||||
},
|
||||
});
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
|
||||
// toggle the messaging menu and open the documentThread
|
||||
testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
await testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
assert.containsOnce(messagingMenu, '.o_mail_preview',
|
||||
"should display one preview");
|
||||
testUtils.dom.click(messagingMenu.$('.o_mail_preview'));
|
||||
await testUtils.dom.click(messagingMenu.$('.o_mail_preview'));
|
||||
assert.strictEqual($('.o_thread_window').length, 1,
|
||||
"should have open the DocumentThread in a thread window");
|
||||
|
||||
@@ -158,12 +158,12 @@ QUnit.test('expand a document thread window', function (assert) {
|
||||
'Open document', "button should have correct title");
|
||||
|
||||
// click to expand
|
||||
testUtils.dom.click($('.o_thread_window .o_thread_window_expand'));
|
||||
await testUtils.dom.click($('.o_thread_window .o_thread_window_expand'));
|
||||
|
||||
messagingMenu.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('post messages in a document thread window', function (assert) {
|
||||
QUnit.test('post messages in a document thread window', async function (assert) {
|
||||
assert.expect(8);
|
||||
|
||||
var newMessageBody = 'Some message';
|
||||
@@ -193,7 +193,7 @@ QUnit.test('post messages in a document thread window', function (assert) {
|
||||
// add the message to the fake DB
|
||||
this.data['mail.message'].records.push(newMessage);
|
||||
this.data['some.res.model'].records[0].message_ids.push(6783);
|
||||
return $.when(6783);
|
||||
return Promise.resolve(6783);
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
@@ -205,73 +205,74 @@ QUnit.test('post messages in a document thread window', function (assert) {
|
||||
"should write sent message in local storage, to share info with other tabs");
|
||||
}
|
||||
}, true);
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
|
||||
// toggle the messaging menu and open the documentThread
|
||||
testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
await testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
assert.containsOnce(messagingMenu, '.o_mail_preview',
|
||||
"should display one preview");
|
||||
testUtils.dom.click(messagingMenu.$('.o_mail_preview'));
|
||||
await testUtils.dom.click(messagingMenu.$('.o_mail_preview'));
|
||||
assert.strictEqual($('.o_thread_window').length, 1,
|
||||
"should have open the DocumentThread in a thread window");
|
||||
assert.strictEqual($('.o_thread_window .o_thread_message').length, 2,
|
||||
"should display 2 messages in the thread window");
|
||||
|
||||
// post a message
|
||||
$('.o_thread_window .o_composer_text_field')
|
||||
.val(newMessageBody)
|
||||
.trigger($.Event('keydown', {which: $.ui.keyCode.ENTER}));
|
||||
|
||||
await testUtils.fields.editAndTrigger($('.o_thread_window .o_composer_text_field'), newMessageBody,
|
||||
[$.Event('keydown', {which: $.ui.keyCode.ENTER})]);
|
||||
assert.strictEqual($('.o_thread_window .o_thread_message').length, 3,
|
||||
"should display 3 messages in the thread window");
|
||||
|
||||
messagingMenu.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('open, fold, unfold and close a document thread window', function (assert) {
|
||||
QUnit.test('open, fold, unfold and close a document thread window', async function (assert) {
|
||||
assert.expect(8);
|
||||
|
||||
var messagingMenu = new MessagingMenu();
|
||||
testUtils.mock.addMockEnvironment(messagingMenu, {
|
||||
services: this.services,
|
||||
data: this.data,
|
||||
session: this.session,
|
||||
});
|
||||
await testUtils.nextTick();
|
||||
testUtils.mock.intercept(messagingMenu, 'call_service', function (ev) {
|
||||
if (ev.data.service === 'local_storage' && ev.data.method === 'setItem') {
|
||||
assert.step(ev.data.args);
|
||||
assert.step(JSON.stringify(ev.data.args));
|
||||
}
|
||||
}, true);
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
|
||||
// toggle the messaging menu and open the documentThread
|
||||
testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
await testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
assert.containsOnce(messagingMenu, '.o_mail_preview',
|
||||
"should display one preview");
|
||||
testUtils.dom.click(messagingMenu.$('.o_mail_preview'));
|
||||
await testUtils.dom.click(messagingMenu.$('.o_mail_preview'));
|
||||
assert.strictEqual($('.o_thread_window').length, 1,
|
||||
"should have open the DocumentThread in a thread window");
|
||||
assert.strictEqual($('.o_thread_window .o_thread_message').length, 2,
|
||||
"should display 2 messages in the thread window");
|
||||
|
||||
// fold and unfold thread window
|
||||
testUtils.dom.click($('.o_thread_window .o_thread_window_title'));
|
||||
testUtils.dom.click($('.o_thread_window .o_thread_window_title'));
|
||||
await testUtils.dom.click($('.o_thread_window .o_thread_window_title'));
|
||||
await testUtils.nextTick();
|
||||
await testUtils.dom.click($('.o_thread_window .o_thread_window_title'));
|
||||
await testUtils.nextTick();
|
||||
|
||||
// close thread window
|
||||
testUtils.dom.click($('.o_thread_window .o_thread_window_close'));
|
||||
await testUtils.dom.click($('.o_thread_window .o_thread_window_close'));
|
||||
await testUtils.nextTick();
|
||||
|
||||
assert.verifySteps([
|
||||
['mail.document_threads_state', {"some.res.model_1": {"name": "Some Record", "windowState": "open"}}],
|
||||
['mail.document_threads_state', {"some.res.model_1": {"name": "Some Record", "windowState": "folded"}}],
|
||||
['mail.document_threads_state', {"some.res.model_1": {"name": "Some Record", "windowState": "open"}}],
|
||||
['mail.document_threads_state', {"some.res.model_1": {"name": "Some Record", "windowState": "closed"}}],
|
||||
'["mail.document_threads_state",{"some.res.model_1":{"name":"Some Record","windowState":"open"}}]',
|
||||
'["mail.document_threads_state",{"some.res.model_1":{"name":"Some Record","windowState":"folded"}}]',
|
||||
'["mail.document_threads_state",{"some.res.model_1":{"name":"Some Record","windowState":"open"}}]',
|
||||
'["mail.document_threads_state",{"some.res.model_1":{"name":"Some Record","windowState":"closed"}}]',
|
||||
]);
|
||||
|
||||
messagingMenu.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('do not open thread window on fetch message failure', function (assert) {
|
||||
QUnit.test('do not open thread window on fetch message failure', async function (assert) {
|
||||
// this may happen when the user receives a notification from a document
|
||||
// that he does not have access rights at the moment.
|
||||
assert.expect(4);
|
||||
@@ -284,17 +285,17 @@ QUnit.test('do not open thread window on fetch message failure', function (asser
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'read' && args.model === 'some.res.model' && args.args[0][0] === 1) {
|
||||
assert.step('some.res.model/1/read');
|
||||
return $.Deferred().reject(); // simulate failure
|
||||
return Promise.reject(); // simulate failure
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
|
||||
testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
await testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
assert.containsOnce(messagingMenu, '.o_mail_preview');
|
||||
|
||||
testUtils.dom.click(messagingMenu.$('.o_mail_preview'));
|
||||
await testUtils.dom.click(messagingMenu.$('.o_mail_preview'));
|
||||
assert.verifySteps(['some.res.model/1/read']);
|
||||
assert.strictEqual($('.o_thread_window').length, 0,
|
||||
"should not have open the DocumentThread in a thread window on fetch messages failure");
|
||||
|
||||
@@ -20,16 +20,16 @@ var createViewer = function (params) {
|
||||
|
||||
var mockRPC = function (route) {
|
||||
if (route === '/web/static/lib/pdfjs/web/viewer.html?file=/web/content/1?model%3Dir.attachment') {
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (route === 'https://www.youtube.com/embed/FYqW0Gdwbzk') {
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (route === '/web/content/4?model%3Dir.attachment') {
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (route === '/web/image/6?unique=1&signature=999&model=ir.attachment') {
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
}
|
||||
};
|
||||
testUtils.mock.addMockEnvironment(parent, {
|
||||
@@ -51,14 +51,15 @@ var createViewer = function (params) {
|
||||
$target = $('body');
|
||||
$target.addClass('debug');
|
||||
}
|
||||
viewer.appendTo($target);
|
||||
|
||||
// actually destroy the parent when the viewer is destroyed
|
||||
viewer.destroy = function () {
|
||||
delete viewer.destroy;
|
||||
parent.destroy();
|
||||
};
|
||||
return viewer;
|
||||
return viewer.appendTo($target).then(function() {
|
||||
return viewer;
|
||||
});
|
||||
};
|
||||
|
||||
QUnit.module('DocumentViewer', {
|
||||
@@ -74,10 +75,10 @@ QUnit.module('DocumentViewer', {
|
||||
},
|
||||
}, function () {
|
||||
|
||||
QUnit.test('basic rendering', function (assert) {
|
||||
QUnit.test('basic rendering', async function (assert) {
|
||||
assert.expect(7);
|
||||
|
||||
var viewer = createViewer({
|
||||
var viewer = await createViewer({
|
||||
attachmentID: 1,
|
||||
attachments: this.attachments,
|
||||
});
|
||||
@@ -100,11 +101,11 @@ QUnit.module('DocumentViewer', {
|
||||
viewer.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('Document Viewer Youtube', function (assert) {
|
||||
QUnit.test('Document Viewer Youtube', async function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
var youtubeURL = 'https://www.youtube.com/embed/FYqW0Gdwbzk';
|
||||
var viewer = createViewer({
|
||||
var viewer = await createViewer({
|
||||
attachmentID: 2,
|
||||
attachments: this.attachments,
|
||||
mockRPC: function (route) {
|
||||
@@ -123,10 +124,10 @@ QUnit.module('DocumentViewer', {
|
||||
viewer.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('Document Viewer html/(txt)', function (assert) {
|
||||
QUnit.test('Document Viewer html/(txt)', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
var viewer = createViewer({
|
||||
var viewer = await createViewer({
|
||||
attachmentID: 4,
|
||||
attachments: this.attachments,
|
||||
});
|
||||
@@ -139,10 +140,10 @@ QUnit.module('DocumentViewer', {
|
||||
viewer.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('Document Viewer mp4', function (assert) {
|
||||
QUnit.test('Document Viewer mp4', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
var viewer = createViewer({
|
||||
var viewer = await createViewer({
|
||||
attachmentID: 5,
|
||||
attachments: this.attachments,
|
||||
});
|
||||
@@ -155,10 +156,10 @@ QUnit.module('DocumentViewer', {
|
||||
viewer.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('Document Viewer jpg', function (assert) {
|
||||
QUnit.test('Document Viewer jpg', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
var viewer = createViewer({
|
||||
var viewer = await createViewer({
|
||||
attachmentID: 6,
|
||||
attachments: this.attachments,
|
||||
});
|
||||
@@ -171,10 +172,10 @@ QUnit.module('DocumentViewer', {
|
||||
viewer.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('is closable by button', function (assert) {
|
||||
QUnit.test('is closable by button', async function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
var viewer = createViewer({
|
||||
var viewer = await createViewer({
|
||||
attachmentID: 6,
|
||||
attachments: this.attachments,
|
||||
});
|
||||
@@ -184,15 +185,15 @@ QUnit.module('DocumentViewer', {
|
||||
assert.containsOnce(viewer, '.o_close_btn',
|
||||
"should have a close button");
|
||||
|
||||
testUtils.dom.click(viewer.$('.o_close_btn'));
|
||||
await testUtils.dom.click(viewer.$('.o_close_btn'));
|
||||
|
||||
assert.ok(viewer.isDestroyed(), 'viewer should be destroyed');
|
||||
});
|
||||
|
||||
QUnit.test('is closable by clicking on the wrapper', function (assert) {
|
||||
QUnit.test('is closable by clicking on the wrapper', async function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
var viewer = createViewer({
|
||||
var viewer = await createViewer({
|
||||
attachmentID: 6,
|
||||
attachments: this.attachments,
|
||||
});
|
||||
@@ -202,7 +203,7 @@ QUnit.module('DocumentViewer', {
|
||||
assert.containsOnce(viewer, '.o_viewer_img_wrapper',
|
||||
"should have a wrapper");
|
||||
|
||||
testUtils.dom.click(viewer.$('.o_viewer_img_wrapper'));
|
||||
await testUtils.dom.click(viewer.$('.o_viewer_img_wrapper'));
|
||||
|
||||
assert.ok(viewer.isDestroyed(), 'viewer should be destroyed');
|
||||
});
|
||||
|
||||
@@ -183,29 +183,29 @@ MockServer.include({
|
||||
_performRpc: function (route, args) {
|
||||
// routes
|
||||
if (route === '/mail/init_messaging') {
|
||||
return $.when(this._mockInitMessaging(args));
|
||||
return Promise.resolve(this._mockInitMessaging(args));
|
||||
}
|
||||
// methods
|
||||
if (args.method === 'channel_fetch_listeners') {
|
||||
return $.when([]);
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
if (args.method === 'channel_fetch_preview') {
|
||||
return $.when(this._mockChannelFetchPreview(args));
|
||||
return Promise.resolve(this._mockChannelFetchPreview(args));
|
||||
}
|
||||
if (args.method === 'channel_minimize') {
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (args.method === 'channel_seen') {
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (args.method === 'channel_fetched') {
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (args.method === 'message_fetch') {
|
||||
return $.when(this._mockMessageFetch(args));
|
||||
return Promise.resolve(this._mockMessageFetch(args));
|
||||
}
|
||||
if (args.method === 'message_format') {
|
||||
return $.when(this._mockMessageFormat(args));
|
||||
return Promise.resolve(this._mockMessageFormat(args));
|
||||
}
|
||||
if (args.method === 'activity_format') {
|
||||
var res = this._mockRead(args.model, args.args, args.kwargs);
|
||||
@@ -217,19 +217,19 @@ MockServer.include({
|
||||
}
|
||||
return record;
|
||||
});
|
||||
return $.when(res);
|
||||
return Promise.resolve(res);
|
||||
}
|
||||
if (args.method === 'set_message_done') {
|
||||
return $.when(this._mockSetMessageDone(args));
|
||||
return Promise.resolve(this._mockSetMessageDone(args));
|
||||
}
|
||||
if (args.method === 'moderate') {
|
||||
return $.when(this._mockModerate(args));
|
||||
return Promise.resolve(this._mockModerate(args));
|
||||
}
|
||||
if (args.method === 'notify_typing') {
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (args.method === 'set_message_done') {
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
}
|
||||
return this._super(route, args);
|
||||
},
|
||||
|
||||
@@ -26,9 +26,9 @@ var Widget = require('web.Widget');
|
||||
* This is async due to mail_manager/mail_service that needs to be ready.
|
||||
*
|
||||
* @param {Object} params
|
||||
* @return {$.Promise} resolved with the discuss widget
|
||||
* @return {Promise} resolved with the discuss widget
|
||||
*/
|
||||
function createDiscuss(params) {
|
||||
async function createDiscuss(params) {
|
||||
var Parent = Widget.extend({
|
||||
do_push_state: function () {},
|
||||
});
|
||||
@@ -49,7 +49,7 @@ function createDiscuss(params) {
|
||||
parent.destroy();
|
||||
};
|
||||
|
||||
return discuss.appendTo($(selector)).then(function () {
|
||||
return discuss.appendTo($(selector)).then(function () {
|
||||
return discuss;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ QUnit.test('simple set im_status', function (assert) {
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('multi get_im_status', function (assert) {
|
||||
QUnit.test('multi get_im_status', async function (assert) {
|
||||
assert.expect(9);
|
||||
var readCount = 0;
|
||||
var parent = testUtils.createParent({
|
||||
@@ -52,7 +52,7 @@ QUnit.test('multi get_im_status', function (assert) {
|
||||
assert.deepEqual(args.args[0], [2,3]);
|
||||
assert.deepEqual(args.args[1], ['id', 'im_status']);
|
||||
readCount++;
|
||||
return $.when([
|
||||
return Promise.resolve([
|
||||
{id: 2, im_status: 'away'},
|
||||
{id: 3, im_status: 'im_partner'}
|
||||
]);
|
||||
@@ -64,22 +64,27 @@ QUnit.test('multi get_im_status', function (assert) {
|
||||
id: 1,
|
||||
im_status: 'online',
|
||||
}]);
|
||||
await testUtils.nextTick();
|
||||
assert.strictEqual(parent.call('mail_service', 'getImStatus', { partnerID: 1 }), 'online');
|
||||
assert.strictEqual(parent.call('mail_service', 'getImStatus', { partnerID: 2 }), undefined);
|
||||
assert.strictEqual(parent.call('mail_service', 'getImStatus', { partnerID: 3 }), undefined);
|
||||
|
||||
this.timeoutMock.runPendingTimeouts();
|
||||
await testUtils.nextTick();
|
||||
|
||||
assert.strictEqual(parent.call('mail_service', 'getImStatus', { partnerID: 1 }), 'online');
|
||||
assert.strictEqual(parent.call('mail_service', 'getImStatus', { partnerID: 2 }), 'away');
|
||||
assert.strictEqual(parent.call('mail_service', 'getImStatus', { partnerID: 3 }), 'im_partner');
|
||||
|
||||
this.timeoutMock.runPendingTimeouts();
|
||||
await testUtils.nextTick();
|
||||
|
||||
assert.strictEqual(readCount, 1, 'Only one read on partner should have been performed');
|
||||
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('update loop', function (assert) {
|
||||
QUnit.test('update loop', async function (assert) {
|
||||
assert.expect(12);
|
||||
var readCount = 0;
|
||||
var parent = testUtils.createParent({
|
||||
@@ -92,7 +97,7 @@ QUnit.test('update loop', function (assert) {
|
||||
assert.deepEqual(args.args[0], [1, 2]);
|
||||
assert.deepEqual(args.args[1], ['id', 'im_status']);
|
||||
readCount++;
|
||||
return $.when([
|
||||
return Promise.resolve([
|
||||
{"id": 1, "im_status": "online"},
|
||||
{"id": 2, "im_status": "away"}
|
||||
]);
|
||||
@@ -106,11 +111,14 @@ QUnit.test('update loop', function (assert) {
|
||||
{ id: 2, im_status: 'offline' },
|
||||
{ id: 3, im_status: 'im_partner' }, //shouldn't be updated !!!!
|
||||
]);
|
||||
await testUtils.nextTick();
|
||||
//_updateImStatusLoop should be running at one second per iteration, lets make a minute pass.
|
||||
assert.strictEqual(readCount, 0);
|
||||
this.timeoutMock.addTime(50*1000);
|
||||
await testUtils.nextTick();
|
||||
assert.strictEqual(readCount, 0);
|
||||
this.timeoutMock.addTime(1000);
|
||||
await testUtils.nextTick();
|
||||
assert.strictEqual(readCount, 1, 'one call should have been made after 50 seconds' );
|
||||
assert.strictEqual(parent.call('mail_service', 'getImStatus', { partnerID: 1 }), 'online');
|
||||
assert.strictEqual(parent.call('mail_service', 'getImStatus', { partnerID: 2 }), 'away');
|
||||
@@ -118,21 +126,27 @@ QUnit.test('update loop', function (assert) {
|
||||
//simulate change of focus
|
||||
//original listener: $(window).on("blur", this._onWindowFocusChange.bind(this, false); + unload, ...
|
||||
parent.call('mail_service', '_onWindowFocusChange', false); // remove focus from tab
|
||||
await testUtils.nextTick();
|
||||
|
||||
this.timeoutMock.addTime(5*60*1000); // x minutes without focus, no rpc should be done during this time
|
||||
await testUtils.nextTick();
|
||||
assert.strictEqual(readCount, 1, 'No more call should have been performed');
|
||||
//simulate change of focus
|
||||
//original listener: $(window).on("focus", this._onWindowFocusChange.bind(this, true);
|
||||
parent.call('mail_service', '_onWindowFocusChange', true); // give focus to tab
|
||||
await testUtils.nextTick();
|
||||
var nextUpdateDelay = this.timeoutMock.getNextTimeoutDelay();
|
||||
await testUtils.nextTick();
|
||||
assert.strictEqual(nextUpdateDelay, 1000, "next update should be done in maximum one second");
|
||||
this.timeoutMock.addTime(nextUpdateDelay); // one second should be enough
|
||||
await testUtils.nextTick();
|
||||
assert.strictEqual(readCount, 2, 'One more call should have been done once tab focused');
|
||||
this.timeoutMock.runPendingTimeouts();
|
||||
await testUtils.nextTick();
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('update status', function (assert) {
|
||||
QUnit.test('update status', async function (assert) {
|
||||
// the current solution to look for updatable im_status in dom is not perfect, but waiting for
|
||||
// ability to include widgets in views, this is the most simple solution
|
||||
assert.expect(2);
|
||||
@@ -159,7 +173,7 @@ QUnit.test('update status', function (assert) {
|
||||
throw new Error(_.str.sprintf('No rpc call should be performed: %s, %s \n %s', args.model, args.method, route));
|
||||
},
|
||||
});
|
||||
statusWidget.appendTo($('#qunit-fixture'));
|
||||
await statusWidget.appendTo($('#qunit-fixture'));
|
||||
//Render unknow im_status:
|
||||
// set initial status
|
||||
assert.ok(statusWidget.$('.o_updatable_im_status i').hasClass('o_user_online'));
|
||||
@@ -167,6 +181,7 @@ QUnit.test('update status', function (assert) {
|
||||
statusWidget.call('mail_service', 'updateImStatus', [
|
||||
{ id: 1, im_status: 'offline' },
|
||||
]);
|
||||
await testUtils.nextTick();
|
||||
assert.notOk(statusWidget.$('.o_updatable_im_status i').hasClass('o_user_online'));
|
||||
this.timeoutMock.runPendingTimeouts();
|
||||
statusWidget.destroy();
|
||||
|
||||
@@ -10,7 +10,7 @@ QUnit.module('mail', {
|
||||
beforeEach: function () {
|
||||
|
||||
var self = this;
|
||||
this.timeoutCDDef = $.Deferred();
|
||||
this.timeoutCDDef = testUtils.makeTestPromise();
|
||||
|
||||
this.patch = function () {
|
||||
self.ORIGINAL_CCTFO_ON_CD_TIMEOUT = CCThrottleFunctionObject.prototype._onCooldownTimeout;
|
||||
@@ -36,7 +36,7 @@ QUnit.test('cancel()', function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
var self = this;
|
||||
var def = $.Deferred();
|
||||
var def = testUtils.makeTestPromise();
|
||||
var step = 1;
|
||||
|
||||
var widget = testUtils.createParent({
|
||||
@@ -52,7 +52,7 @@ QUnit.test('cancel()', function (assert) {
|
||||
}
|
||||
step++;
|
||||
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
@@ -80,7 +80,7 @@ QUnit.test('cancel()', function (assert) {
|
||||
self.timeoutCDDef.resolve();
|
||||
});
|
||||
this.timeoutCDDef.then(function () {
|
||||
assert.verifySteps(['__rpc__1'],
|
||||
assert.verifySteps([],
|
||||
"function should still have been called once after 2nd function call cancelled");
|
||||
widget.destroy();
|
||||
done();
|
||||
@@ -92,8 +92,8 @@ QUnit.test('clear()', function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
var self = this;
|
||||
var def1 = $.Deferred();
|
||||
var def2 = $.Deferred();
|
||||
var def1 = testUtils.makeTestPromise();
|
||||
var def2 = testUtils.makeTestPromise();
|
||||
var step = 1;
|
||||
|
||||
var widget = testUtils.createParent({
|
||||
@@ -110,7 +110,7 @@ QUnit.test('clear()', function (assert) {
|
||||
}
|
||||
step++;
|
||||
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
@@ -135,14 +135,14 @@ QUnit.test('clear()', function (assert) {
|
||||
}).then(function () {
|
||||
cctFunc(2);
|
||||
}).then(function () {
|
||||
assert.verifySteps(['__rpc__1'],
|
||||
assert.verifySteps([],
|
||||
"function should still have been called once (due to long throttle)");
|
||||
cctFunc.clear();
|
||||
self.timeoutCDDef.resolve();
|
||||
def2.resolve();
|
||||
});
|
||||
$.when(self.timeoutCDDef, def2).then(function () {
|
||||
assert.verifySteps(['__rpc__1', '__rpc__2'],
|
||||
Promise.all([self.timeoutCDDef, def2]).then(function () {
|
||||
assert.verifySteps(['__rpc__2'],
|
||||
"function should have been called twice after 'clear' (buffered 2nd function call)");
|
||||
widget.destroy();
|
||||
done();
|
||||
|
||||
@@ -1,31 +1,27 @@
|
||||
odoo.define('mail.model.TimerTests', function (require) {
|
||||
"use strict";
|
||||
|
||||
var testUtils = require("web.test_utils");
|
||||
var Timer = require('mail.model.Timer');
|
||||
|
||||
QUnit.module('mail', {}, function () {
|
||||
QUnit.module('model', {}, function () {
|
||||
QUnit.module('Timer');
|
||||
|
||||
QUnit.test('start()', function (assert) {
|
||||
var done = assert.async();
|
||||
QUnit.test('start()', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
var def = $.Deferred();
|
||||
var func = function () {
|
||||
def.resolve();
|
||||
};
|
||||
var prom = testUtils.makeTestPromise();
|
||||
var t = new Timer({
|
||||
duration: 0,
|
||||
onTimeout: func,
|
||||
onTimeout: prom.resolve,
|
||||
});
|
||||
|
||||
assert.verifySteps([], "should not have called the function");
|
||||
|
||||
t.start();
|
||||
def.then(function () {
|
||||
await prom.then(function () {
|
||||
assert.ok(true, "should have called the function");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -51,11 +47,10 @@ QUnit.test('clear()', function (assert) {
|
||||
}, 0);
|
||||
});
|
||||
|
||||
QUnit.test('reset()', function (assert) {
|
||||
var done = assert.async();
|
||||
QUnit.test('reset()', async function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
var def = $.Deferred();
|
||||
var prom = testUtils.makeTestPromise();
|
||||
var func = function () {
|
||||
assert.step('function_called');
|
||||
};
|
||||
@@ -67,19 +62,17 @@ QUnit.test('reset()', function (assert) {
|
||||
t.start();
|
||||
|
||||
// Called after 1st timer timeout
|
||||
await testUtils.nextTick();
|
||||
assert.verifySteps(['function_called'], "should have called the function once");
|
||||
t.reset();
|
||||
// Called after 2nd timer timeout
|
||||
setTimeout(function () {
|
||||
assert.verifySteps(['function_called'], "should have called the function once");
|
||||
t.reset();
|
||||
// Called after 2nd timer timeout
|
||||
setTimeout(function () {
|
||||
def.resolve();
|
||||
}, 0);
|
||||
prom.resolve();
|
||||
}, 0);
|
||||
|
||||
def.then(function () {
|
||||
assert.verifySteps(['function_called', 'function_called'],
|
||||
await prom.then(function () {
|
||||
assert.verifySteps(['function_called'],
|
||||
"should have called the function twice (2nd time from reset)");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ QUnit.module('ActivityMenu', {
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test('activity menu widget: menu with no records', function (assert) {
|
||||
QUnit.test('activity menu widget: menu with no records', async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var activityMenu = new ActivityMenu();
|
||||
@@ -84,17 +84,18 @@ QUnit.test('activity menu widget: menu with no records', function (assert) {
|
||||
services: this.services,
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'systray_get_activities') {
|
||||
return $.when([]);
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
return this._super(route, args);
|
||||
},
|
||||
});
|
||||
activityMenu.appendTo($('#qunit-fixture'));
|
||||
assert.hasClass(activityMenu.$('.o_no_activity'),'o_no_activity', "should not have instance of widget");
|
||||
await activityMenu.appendTo($('#qunit-fixture'));
|
||||
await testUtils.nextTick();
|
||||
assert.containsOnce(activityMenu, '.o_no_activity');
|
||||
activityMenu.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('activity menu widget: activity menu with 3 records', function (assert) {
|
||||
QUnit.test('activity menu widget: activity menu with 3 records', async function (assert) {
|
||||
assert.expect(10);
|
||||
var self = this;
|
||||
var activityMenu = new ActivityMenu();
|
||||
@@ -102,12 +103,13 @@ QUnit.test('activity menu widget: activity menu with 3 records', function (asser
|
||||
services: this.services,
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'systray_get_activities') {
|
||||
return $.when(self.data['mail.activity.menu']['records']);
|
||||
return Promise.resolve(self.data['mail.activity.menu']['records']);
|
||||
}
|
||||
return this._super(route, args);
|
||||
},
|
||||
});
|
||||
activityMenu.appendTo($('#qunit-fixture'));
|
||||
await activityMenu.appendTo($('#qunit-fixture'));
|
||||
await testUtils.nextTick();
|
||||
assert.hasClass(activityMenu.$el, 'o_mail_systray_item', 'should be the instance of widget');
|
||||
// the assertion below has not been replace because there are includes of ActivityMenu that modify the length.
|
||||
assert.ok(activityMenu.$('.o_mail_preview').length);
|
||||
@@ -123,34 +125,34 @@ QUnit.test('activity menu widget: activity menu with 3 records', function (asser
|
||||
context = {
|
||||
search_default_activities_overdue: 1,
|
||||
};
|
||||
testUtils.dom.click(activityMenu.$('.dropdown-toggle'));
|
||||
await testUtils.dom.click(activityMenu.$('.dropdown-toggle'));
|
||||
assert.hasClass(activityMenu.$el, 'show', 'ActivityMenu should be open');
|
||||
testUtils.dom.click(activityMenu.$(".o_activity_filter_button[data-model_name='Issue'][data-filter='overdue']"));
|
||||
await testUtils.dom.click(activityMenu.$(".o_activity_filter_button[data-model_name='Issue'][data-filter='overdue']"));
|
||||
assert.doesNotHaveClass(activityMenu.$el, 'show', 'ActivityMenu should be closed');
|
||||
// case 2: click on "today"
|
||||
context = {
|
||||
search_default_activities_today: 1,
|
||||
};
|
||||
testUtils.dom.click(activityMenu.$('.dropdown-toggle'));
|
||||
testUtils.dom.click(activityMenu.$(".o_activity_filter_button[data-model_name='Issue'][data-filter='today']"));
|
||||
await testUtils.dom.click(activityMenu.$('.dropdown-toggle'));
|
||||
await testUtils.dom.click(activityMenu.$(".o_activity_filter_button[data-model_name='Issue'][data-filter='today']"));
|
||||
// case 3: click on "future"
|
||||
context = {
|
||||
search_default_activities_upcoming_all: 1,
|
||||
};
|
||||
testUtils.dom.click(activityMenu.$('.dropdown-toggle'));
|
||||
testUtils.dom.click(activityMenu.$(".o_activity_filter_button[data-model_name='Issue'][data-filter='upcoming_all']"));
|
||||
await testUtils.dom.click(activityMenu.$('.dropdown-toggle'));
|
||||
await testUtils.dom.click(activityMenu.$(".o_activity_filter_button[data-model_name='Issue'][data-filter='upcoming_all']"));
|
||||
// case 4: click anywere else
|
||||
context = {
|
||||
search_default_activities_overdue: 1,
|
||||
search_default_activities_today: 1,
|
||||
};
|
||||
testUtils.dom.click(activityMenu.$('.dropdown-toggle'));
|
||||
testUtils.dom.click(activityMenu.$(".o_mail_systray_dropdown_items > div[data-model_name='Issue']"));
|
||||
await testUtils.dom.click(activityMenu.$('.dropdown-toggle'));
|
||||
await testUtils.dom.click(activityMenu.$(".o_mail_systray_dropdown_items > div[data-model_name='Issue']"));
|
||||
|
||||
activityMenu.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('activity menu widget: activity view icon', function (assert) {
|
||||
QUnit.test('activity menu widget: activity view icon', async function (assert) {
|
||||
assert.expect(10);
|
||||
var self = this;
|
||||
var activityMenu = new ActivityMenu();
|
||||
@@ -158,12 +160,13 @@ QUnit.test('activity menu widget: activity view icon', function (assert) {
|
||||
services: this.services,
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'systray_get_activities') {
|
||||
return $.when(self.data['mail.activity.menu'].records);
|
||||
return Promise.resolve(self.data['mail.activity.menu'].records);
|
||||
}
|
||||
return this._super(route, args);
|
||||
},
|
||||
});
|
||||
activityMenu.appendTo($('#qunit-fixture'));
|
||||
await activityMenu.appendTo($('#qunit-fixture'));
|
||||
await testUtils.nextTick();
|
||||
assert.containsN(activityMenu, '.o_mail_activity_action', 2,
|
||||
"widget should have 2 activity view icons");
|
||||
|
||||
@@ -189,11 +192,11 @@ QUnit.test('activity menu widget: activity view icon', function (assert) {
|
||||
}, true);
|
||||
|
||||
// click on the "Issue" activity icon
|
||||
testUtils.dom.click(activityMenu.$('.dropdown-toggle'));
|
||||
testUtils.dom.click(activityMenu.$(".o_mail_activity_action[data-model_name='Issue']"));
|
||||
await testUtils.dom.click(activityMenu.$('.dropdown-toggle'));
|
||||
await testUtils.dom.click(activityMenu.$(".o_mail_activity_action[data-model_name='Issue']"));
|
||||
|
||||
// click on the "Note" activity icon
|
||||
testUtils.dom.click(activityMenu.$(".o_mail_activity_action[data-model_name='Note']"));
|
||||
await testUtils.dom.click(activityMenu.$(".o_mail_activity_action[data-model_name='Note']"));
|
||||
|
||||
assert.verifySteps([
|
||||
'do_action:Issue',
|
||||
|
||||
@@ -66,7 +66,7 @@ QUnit.module('MessagingMenu (Mail Failures)', {
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test('preview of mail failure', function (assert) {
|
||||
QUnit.test('preview of mail failure', async function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
this.data['mail.message'].records = [{
|
||||
@@ -86,8 +86,8 @@ QUnit.test('preview of mail failure', function (assert) {
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
await testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
|
||||
assert.containsOnce(messagingMenu, '.o_mail_preview',
|
||||
"should display one preview for the mail failure");
|
||||
@@ -101,7 +101,7 @@ QUnit.test('preview of mail failure', function (assert) {
|
||||
messagingMenu.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('preview grouped failures by document', function (assert) {
|
||||
QUnit.test('preview grouped failures by document', async function (assert) {
|
||||
// If some failures linked to a document refers to a same document, a single
|
||||
// preview should group all those failures
|
||||
assert.expect(3);
|
||||
@@ -142,8 +142,8 @@ QUnit.test('preview grouped failures by document', function (assert) {
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
await testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
|
||||
assert.containsN(messagingMenu, '.o_mail_preview', 2,
|
||||
"should have a two messaging previews for the mail failures");
|
||||
@@ -156,7 +156,7 @@ QUnit.test('preview grouped failures by document', function (assert) {
|
||||
messagingMenu.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('preview grouped failures by document model', function (assert) {
|
||||
QUnit.test('preview grouped failures by document model', async function (assert) {
|
||||
// If all failures linked to a document model refers to different documents,
|
||||
// a single preview should group all failures that are linked to this
|
||||
// document model
|
||||
@@ -198,8 +198,8 @@ QUnit.test('preview grouped failures by document model', function (assert) {
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
await testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
|
||||
assert.containsN(messagingMenu, '.o_mail_preview', 2,
|
||||
"should have a two messaging previews for the mail failures");
|
||||
|
||||
@@ -101,7 +101,7 @@ QUnit.module('MessagingMenu', {
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test('messaging menu widget: menu with no records', function (assert) {
|
||||
QUnit.test('messaging menu widget: menu with no records', async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var messagingMenu = new MessagingMenu();
|
||||
@@ -109,27 +109,27 @@ QUnit.test('messaging menu widget: menu with no records', function (assert) {
|
||||
services: this.services,
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'message_fetch') {
|
||||
return $.when([]);
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
}
|
||||
});
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
await testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
assert.hasClass(messagingMenu.$('.o_no_activity'),'o_no_activity', "should not have instance of widget");
|
||||
messagingMenu.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('messaging menu widget: messaging menu with 1 record', function (assert) {
|
||||
QUnit.test('messaging menu widget: messaging menu with 1 record', async function (assert) {
|
||||
assert.expect(3);
|
||||
var messagingMenu = new MessagingMenu();
|
||||
testUtils.mock.addMockEnvironment(messagingMenu, {
|
||||
services: this.services,
|
||||
data: this.data,
|
||||
});
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
|
||||
testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
await testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
|
||||
assert.containsOnce(messagingMenu, '.o_mail_preview',
|
||||
"should display a preview");
|
||||
@@ -146,7 +146,7 @@ QUnit.test('messaging menu widget: messaging menu with 1 record', function (asse
|
||||
messagingMenu.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('messaging menu widget: open inbox for needaction not linked to any document', function (assert) {
|
||||
QUnit.test('messaging menu widget: open inbox for needaction not linked to any document', async function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
var messagingMenu = new MessagingMenu();
|
||||
@@ -157,7 +157,7 @@ QUnit.test('messaging menu widget: open inbox for needaction not linked to any d
|
||||
partner_id: 1,
|
||||
},
|
||||
});
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
|
||||
// Simulate received needaction message without associated document,
|
||||
// so that we have a message in inbox without a model and a resID
|
||||
@@ -174,7 +174,7 @@ QUnit.test('messaging menu widget: open inbox for needaction not linked to any d
|
||||
messagingMenu.call('bus_service', 'trigger', 'notification', notifications);
|
||||
|
||||
// Open messaging menu
|
||||
testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
await testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
|
||||
var $firstChannelPreview =
|
||||
messagingMenu.$('.o_mail_preview').first();
|
||||
@@ -190,7 +190,7 @@ QUnit.test('messaging menu widget: open inbox for needaction not linked to any d
|
||||
assert.step('do_action:' + ev.data.action + ':' + ev.data.options.active_id);
|
||||
}
|
||||
}, true);
|
||||
testUtils.dom.click($firstChannelPreview);
|
||||
await testUtils.dom.click($firstChannelPreview);
|
||||
assert.verifySteps(
|
||||
['do_action:mail.action_discuss:mailbox_inbox'],
|
||||
"should open Discuss with Inbox");
|
||||
@@ -198,7 +198,7 @@ QUnit.test('messaging menu widget: open inbox for needaction not linked to any d
|
||||
messagingMenu.destroy();
|
||||
});
|
||||
|
||||
QUnit.test("messaging menu widget: mark as read on thread preview", function ( assert ) {
|
||||
QUnit.test("messaging menu widget: mark as read on thread preview", async function ( assert ) {
|
||||
assert.expect(8);
|
||||
|
||||
testUtils.mock.patch(DocumentThread, {
|
||||
@@ -230,8 +230,8 @@ QUnit.test("messaging menu widget: mark as read on thread preview", function ( a
|
||||
data: this.data,
|
||||
});
|
||||
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
await testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
assert.hasClass(messagingMenu.$el,'o_mail_systray_item',
|
||||
'should be the instance of widget');
|
||||
assert.hasClass(messagingMenu.$el,'show',
|
||||
@@ -247,7 +247,7 @@ QUnit.test("messaging menu widget: mark as read on thread preview", function ( a
|
||||
assert.containsOnce(messagingMenu, '.o_mail_preview_mark_as_read',
|
||||
"should have mark as read icon next to preview");
|
||||
|
||||
testUtils.dom.click(messagingMenu.$(".o_mail_preview_mark_as_read"));
|
||||
await testUtils.dom.click(messagingMenu.$(".o_mail_preview_mark_as_read"));
|
||||
|
||||
assert.verifySteps(['markedAsRead'],
|
||||
"the document thread should be marked as read");
|
||||
@@ -256,7 +256,7 @@ QUnit.test("messaging menu widget: mark as read on thread preview", function ( a
|
||||
messagingMenu.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('needaction messages in channels should appear, in addition to channel preview', function (assert) {
|
||||
QUnit.test('needaction messages in channels should appear, in addition to channel preview', async function (assert) {
|
||||
// Let's suppose a channel whose before-last message (msg1) is a needaction,
|
||||
// but not the last message (msg2). In that case, the systray messaging
|
||||
// menu should display the needaction message msg1 in the preview, and the
|
||||
@@ -295,9 +295,9 @@ QUnit.test('needaction messages in channels should appear, in addition to channe
|
||||
partner_id: partnerID,
|
||||
},
|
||||
});
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
|
||||
testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
await testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
|
||||
assert.containsN(messagingMenu, '.o_mail_preview', 2,
|
||||
"should display two previews");
|
||||
@@ -314,7 +314,7 @@ QUnit.test('needaction messages in channels should appear, in addition to channe
|
||||
messagingMenu.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('preview of message on a document + mark as read', function (assert) {
|
||||
QUnit.test('preview of message on a document + mark as read', async function (assert) {
|
||||
assert.expect(7);
|
||||
|
||||
this.data.initMessaging = {
|
||||
@@ -351,11 +351,11 @@ QUnit.test('preview of message on a document + mark as read', function (assert)
|
||||
partner_id: partnerID,
|
||||
},
|
||||
});
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
assert.strictEqual(messagingMenu.$('.o_notification_counter').text(), '1',
|
||||
"should display a counter of 1 on the messaging menu icon");
|
||||
|
||||
testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
await testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
|
||||
assert.containsOnce(messagingMenu, '.o_mail_preview',
|
||||
"should display one preview");
|
||||
@@ -367,7 +367,7 @@ QUnit.test('preview of message on a document + mark as read', function (assert)
|
||||
assert.strictEqual(messagingMenu.$('.o_preview_unread .o_last_message_preview').text().replace(/\s/g, ''),
|
||||
"Demo:*MessageOnDocument*", "should correctly display the preview");
|
||||
|
||||
testUtils.dom.click(messagingMenu.$('.o_mail_preview_mark_as_read'));
|
||||
await testUtils.dom.click(messagingMenu.$('.o_mail_preview_mark_as_read'));
|
||||
assert.strictEqual(messagingMenu.$('.o_notification_counter').text(), '0',
|
||||
"should display a counter of 0 on the messaging menu icon");
|
||||
assert.containsNone(messagingMenu, '.o_mail_preview',
|
||||
@@ -376,7 +376,7 @@ QUnit.test('preview of message on a document + mark as read', function (assert)
|
||||
messagingMenu.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('update messaging preview on receiving a new message in channel preview', function (assert) {
|
||||
QUnit.test('update messaging preview on receiving a new message in channel preview', async function (assert) {
|
||||
assert.expect(8);
|
||||
|
||||
var messagingMenu = new MessagingMenu();
|
||||
@@ -384,9 +384,9 @@ QUnit.test('update messaging preview on receiving a new message in channel previ
|
||||
services: this.services,
|
||||
data: this.data,
|
||||
});
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
|
||||
testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
await testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
|
||||
assert.containsOnce(messagingMenu, '.o_mail_preview',
|
||||
"should display a single channel preview");
|
||||
@@ -410,7 +410,7 @@ QUnit.test('update messaging preview on receiving a new message in channel previ
|
||||
};
|
||||
var notification = [[false, 'mail.channel', 1], data];
|
||||
messagingMenu.call('bus_service', 'trigger', 'notification', [notification]);
|
||||
|
||||
await testUtils.nextTick();
|
||||
assert.containsOnce(messagingMenu, '.o_mail_preview',
|
||||
"should still display a single channel preview");
|
||||
assert.strictEqual(messagingMenu.$('.o_preview_name').text().trim(), "general",
|
||||
@@ -427,7 +427,7 @@ 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) {
|
||||
QUnit.test('preview of inbox message not linked to document + mark as read', async function (assert) {
|
||||
assert.expect(17);
|
||||
|
||||
this.data.initMessaging = {
|
||||
@@ -459,19 +459,16 @@ QUnit.test('preview of inbox message not linked to document + mark as read', fun
|
||||
},
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'set_message_done') {
|
||||
assert.step({
|
||||
method: 'set_message_done',
|
||||
messageIDs: args.args[0],
|
||||
});
|
||||
assert.step('method: set_message_done, messageIDs: ' + JSON.stringify(args.args[0]));
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
await 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();
|
||||
await testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
|
||||
assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 2,
|
||||
"should display two previews");
|
||||
@@ -494,11 +491,9 @@ QUnit.test('preview of inbox message not linked to document + mark as read', fun
|
||||
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");
|
||||
await testUtils.dom.click($preview1.find('.o_mail_preview_mark_as_read'));
|
||||
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,
|
||||
@@ -507,14 +502,9 @@ QUnit.test('preview of inbox message not linked to document + mark as read', fun
|
||||
"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");
|
||||
await testUtils.dom.click($preview2.find('.o_mail_preview_mark_as_read'));
|
||||
assert.verifySteps(['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,
|
||||
@@ -523,7 +513,7 @@ QUnit.test('preview of inbox message not linked to document + mark as read', fun
|
||||
messagingMenu.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('grouped preview for needaction messages linked to same document', function (assert) {
|
||||
QUnit.test('grouped preview for needaction messages linked to same document', async function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
// simulate two (read) needaction (mention) messages in channel 'general'
|
||||
@@ -561,9 +551,9 @@ QUnit.test('grouped preview for needaction messages linked to same document', fu
|
||||
partner_id: 44,
|
||||
},
|
||||
});
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
|
||||
messagingMenu.$('.dropdown-toggle').click();
|
||||
await testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
var $previews = messagingMenu.$('.o_mail_preview');
|
||||
|
||||
assert.strictEqual($previews.length, 2,
|
||||
@@ -586,7 +576,7 @@ QUnit.test('grouped preview for needaction messages linked to same document', fu
|
||||
messagingMenu.destroy();
|
||||
});
|
||||
|
||||
QUnit.test("messaging menu widget: channel seen notification", function (assert) {
|
||||
QUnit.test("messaging menu widget: channel seen notification", async function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
this.data.initMessaging.channel_slots = {
|
||||
@@ -606,8 +596,8 @@ QUnit.test("messaging menu widget: channel seen notification", function (assert)
|
||||
session: { partner_id: 3 },
|
||||
});
|
||||
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
messagingMenu.$('.dropdown-toggle').click();
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
await testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
|
||||
assert.strictEqual(messagingMenu.$('.o_notification_counter').text(), '1',
|
||||
"should have correct messaging menu counter (1 unread message in channel)");
|
||||
@@ -625,7 +615,7 @@ QUnit.test("messaging menu widget: channel seen notification", function (assert)
|
||||
[['myDB', 'mail.channel', 1], message]
|
||||
];
|
||||
messagingMenu.call('bus_service', 'trigger', 'notification', notifications);
|
||||
|
||||
await testUtils.nextTick();
|
||||
assert.strictEqual(messagingMenu.$('.o_notification_counter').text(), '0',
|
||||
"should no longer have a messaging menu counter (no unread message in channel)");
|
||||
assert.strictEqual(messagingMenu.$('.o_preview_counter').text().replace(/\s/g, ''), '',
|
||||
@@ -634,7 +624,7 @@ QUnit.test("messaging menu widget: channel seen notification", function (assert)
|
||||
messagingMenu.destroy();
|
||||
});
|
||||
|
||||
QUnit.test("messaging menu widget: no traceback when receiving channel_fetched notification with blank thread window", function (assert) {
|
||||
QUnit.test("messaging menu widget: no traceback when receiving channel_fetched notification with blank thread window", async function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
this.data.initMessaging.channel_slots = {
|
||||
@@ -654,12 +644,12 @@ QUnit.test("messaging menu widget: no traceback when receiving channel_fetched n
|
||||
session: { partner_id: 3 },
|
||||
});
|
||||
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
messagingMenu.$('.dropdown-toggle').click();
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
await testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
assert.containsOnce(messagingMenu, '.o_new_message',
|
||||
"should have button to open blank thread window");
|
||||
|
||||
testUtils.dom.click(messagingMenu.$('.o_new_message'));
|
||||
await testUtils.dom.click(messagingMenu.$('.o_new_message'));
|
||||
var $threadWindow = $('.o_thread_window');
|
||||
assert.strictEqual($threadWindow.length, 1, "should have an open thread window");
|
||||
assert.ok($threadWindow.hasClass('o_thread_less'), "should be a blank thread window");
|
||||
@@ -674,11 +664,12 @@ QUnit.test("messaging menu widget: no traceback when receiving channel_fetched n
|
||||
[['myDB', 'mail.channel', 1], message]
|
||||
];
|
||||
messagingMenu.call('bus_service', 'trigger', 'notification', notifications);
|
||||
await testUtils.nextTick();
|
||||
|
||||
messagingMenu.destroy();
|
||||
});
|
||||
|
||||
QUnit.test("messaging menu widget: preview with no message should be undated", function ( assert ) {
|
||||
QUnit.test("messaging menu widget: preview with no message should be undated", async function ( assert ) {
|
||||
assert.expect(2);
|
||||
|
||||
// remove any message on the channel
|
||||
@@ -691,9 +682,8 @@ QUnit.test("messaging menu widget: preview with no message should be undated", f
|
||||
data: this.data,
|
||||
});
|
||||
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
|
||||
messagingMenu.$('.dropdown-toggle').click();
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
await testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
|
||||
assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 1,
|
||||
"should have two previews in messaging menu");
|
||||
@@ -704,7 +694,7 @@ QUnit.test("messaging menu widget: preview with no message should be undated", f
|
||||
messagingMenu.destroy();
|
||||
});
|
||||
|
||||
QUnit.test("messaging menu widget: sort dated previews before undated previews", function ( assert ) {
|
||||
QUnit.test("messaging menu widget: sort dated previews before undated previews", async function ( assert ) {
|
||||
assert.expect(5);
|
||||
|
||||
var dm = {
|
||||
@@ -722,8 +712,8 @@ QUnit.test("messaging menu widget: sort dated previews before undated previews",
|
||||
data: this.data,
|
||||
});
|
||||
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
messagingMenu.$('.dropdown-toggle').click();
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
await testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
|
||||
assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 2,
|
||||
"should have two previews in messaging menu");
|
||||
@@ -743,7 +733,7 @@ QUnit.test("messaging menu widget: sort dated previews before undated previews",
|
||||
messagingMenu.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('global counter with channel previews', function (assert) {
|
||||
QUnit.test('global counter with channel previews', async function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
var channels = [{
|
||||
@@ -812,11 +802,10 @@ QUnit.test('global counter with channel previews', function (assert) {
|
||||
partner_id: 3,
|
||||
},
|
||||
});
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
await 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();
|
||||
await testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
|
||||
assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 3,
|
||||
"should display 3 previews");
|
||||
@@ -834,7 +823,7 @@ QUnit.test('global counter with channel previews', function (assert) {
|
||||
messagingMenu.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('messaging menu widget: do not open chat window twice on preview clicked', function (assert) {
|
||||
QUnit.test('messaging menu widget: do not open chat window twice on preview clicked', async function (assert) {
|
||||
// This test assumes that a condition for opening chat window is to
|
||||
// successfully fetch messages beforehand.
|
||||
assert.expect(4);
|
||||
@@ -844,7 +833,7 @@ QUnit.test('messaging menu widget: do not open chat window twice on preview clic
|
||||
// This is necessary `message_fetch` on mailbox_inbox is required to
|
||||
// display the previews.
|
||||
var lockMessageFetch = false;
|
||||
var messageFetchDef = $.Deferred();
|
||||
var messageFetchDef = testUtils.makeTestPromise();
|
||||
|
||||
var messagingMenu = new MessagingMenu();
|
||||
testUtils.addMockEnvironment(messagingMenu, {
|
||||
@@ -873,19 +862,20 @@ QUnit.test('messaging menu widget: do not open chat window twice on preview clic
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
messagingMenu.appendTo($('#qunit-fixture'));
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
|
||||
// Opening chat window from messaging menu (pending from `messageFetchDef`)
|
||||
testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
await testUtils.dom.click(messagingMenu.$('.dropdown-toggle'));
|
||||
lockMessageFetch = true;
|
||||
testUtils.dom.click(messagingMenu.$('.o_mail_preview'));
|
||||
await testUtils.dom.click(messagingMenu.$('.o_mail_preview'));
|
||||
messageFetchDef.resolve();
|
||||
|
||||
await testUtils.nextTick();
|
||||
assert.strictEqual($('.o_thread_window').length, 1,
|
||||
"should only display a single chat window");
|
||||
assert.verifySteps([
|
||||
'channel_minimize',
|
||||
'message_fetch',
|
||||
'channel_minimize',
|
||||
], "should have fetched messages only once");
|
||||
|
||||
messagingMenu.destroy();
|
||||
|
||||
@@ -55,7 +55,7 @@ QUnit.module('Basic', {
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test('basic rendering thread window', function (assert) {
|
||||
QUnit.test('basic rendering thread window', async function (assert) {
|
||||
assert.expect(10);
|
||||
|
||||
var parent = this.createParent({
|
||||
@@ -63,9 +63,13 @@ QUnit.test('basic rendering thread window', function (assert) {
|
||||
services: this.services,
|
||||
});
|
||||
|
||||
await testUtils.nextTick();
|
||||
// detach channel 1, so that it opens corresponding thread window.
|
||||
parent.call('mail_service', 'getChannel', 1).detach();
|
||||
var result = parent.call('mail_service', 'getChannel', 1);
|
||||
await testUtils.nextTick();
|
||||
result.detach();
|
||||
|
||||
await testUtils.nextTick();
|
||||
var $threadWindow = $('.o_thread_window');
|
||||
assert.strictEqual($threadWindow.length, 1,
|
||||
"thread window should be open");
|
||||
@@ -98,7 +102,7 @@ QUnit.test('basic rendering thread window', function (assert) {
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('close thread window using ESCAPE key', function (assert) {
|
||||
QUnit.test('close thread window using ESCAPE key', async function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
var parent = this.createParent({
|
||||
@@ -107,28 +111,31 @@ QUnit.test('close thread window using ESCAPE key', function (assert) {
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'channel_fold') {
|
||||
assert.ok(true, "should call channel_fold");
|
||||
return $.when();
|
||||
return Promise.resolve();
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
await testUtils.nextTick();
|
||||
|
||||
// get channel instance to link to thread window
|
||||
var channel = parent.call('mail_service', 'getChannel', 1);
|
||||
await testUtils.nextTick();
|
||||
assert.ok(channel, "there should exist a channel locally with ID 1");
|
||||
|
||||
channel.detach();
|
||||
await testUtils.nextTick();
|
||||
assert.strictEqual($('.o_thread_window').length, 1,
|
||||
"there should be a thread window that is opened");
|
||||
|
||||
// focus on the thread window and press ESCAPE
|
||||
testUtils.dom.click($('.o_thread_window .o_composer_text_field'));
|
||||
await testUtils.dom.click($('.o_thread_window .o_composer_text_field'));
|
||||
assert.strictEqual(document.activeElement,
|
||||
$('.o_thread_window .o_composer_text_field')[0],
|
||||
"thread window's input should now be focused");
|
||||
|
||||
var upKeyEvent = $.Event( "keyup", { which: 27 });
|
||||
$('.o_thread_window .o_composer_text_field').trigger(upKeyEvent);
|
||||
await testUtils.dom.triggerEvents($('.o_thread_window .o_composer_text_field'), [upKeyEvent]);
|
||||
|
||||
assert.strictEqual($('.o_thread_window').length, 0,
|
||||
"the thread window should be closed");
|
||||
@@ -136,7 +143,7 @@ QUnit.test('close thread window using ESCAPE key', function (assert) {
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('thread window\'s input can still be focused when the UI is blocked', function (assert) {
|
||||
QUnit.test('thread window\'s input can still be focused when the UI is blocked', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
var parent = this.createParent({
|
||||
@@ -147,11 +154,13 @@ QUnit.test('thread window\'s input can still be focused when the UI is blocked',
|
||||
var $dom = $('#qunit-fixture');
|
||||
|
||||
// get channel instance to link to thread window
|
||||
await testUtils.nextTick();
|
||||
var channel = parent.call('mail_service', 'getChannel', 1);
|
||||
await testUtils.nextTick();
|
||||
channel.detach();
|
||||
|
||||
await testUtils.nextTick();
|
||||
var $input = $('<input/>', {type: 'text'}).appendTo($dom);
|
||||
testUtils.dom.click($input.focus());
|
||||
await testUtils.dom.click($input.focus());
|
||||
assert.strictEqual(document.activeElement, $input[0],
|
||||
"fake input should be focused");
|
||||
|
||||
@@ -160,16 +169,17 @@ QUnit.test('thread window\'s input can still be focused when the UI is blocked',
|
||||
// makes no sense, this test is just about
|
||||
// making sure that the code which forces the
|
||||
// focus on click is not removed
|
||||
testUtils.dom.click($('.o_thread_window .o_composer_text_field'));
|
||||
await testUtils.dom.click($('.o_thread_window .o_composer_text_field'));
|
||||
assert.strictEqual(document.activeElement,
|
||||
$('.o_thread_window .o_composer_text_field')[0],
|
||||
"thread window's input should now be focused");
|
||||
|
||||
framework.unblockUI();
|
||||
parent.destroy();
|
||||
$input.remove();
|
||||
});
|
||||
|
||||
QUnit.test('emoji popover should open correctly in thread windows', function (assert) {
|
||||
QUnit.test('emoji popover should open correctly in thread windows', async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var parent = this.createParent({
|
||||
@@ -178,23 +188,20 @@ QUnit.test('emoji popover should open correctly in thread windows', function (as
|
||||
});
|
||||
|
||||
// get channel instance to link to thread window
|
||||
await testUtils.nextTick();
|
||||
var channel = parent.call('mail_service', 'getChannel', 1);
|
||||
await testUtils.nextTick();
|
||||
channel.detach();
|
||||
|
||||
await testUtils.nextTick();
|
||||
var $emojiButton = $('.o_composer_button_emoji');
|
||||
testUtils.dom.click($emojiButton.trigger('focusin').focus());
|
||||
await testUtils.dom.click($emojiButton.trigger('focusin').focus());
|
||||
var $popover = $('.o_mail_emoji_container');
|
||||
|
||||
var done = assert.async();
|
||||
// Async is needed as the popover focusout hiding is deferred
|
||||
setTimeout(function () {
|
||||
assert.ok($popover.is(':visible'), "emoji popover should have stayed opened");
|
||||
parent.destroy();
|
||||
done();
|
||||
}, 0);
|
||||
assert.ok($popover.is(':visible'), "emoji popover should have stayed opened");
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('do not increase unread counter when receiving message with myself as author', function (assert) {
|
||||
QUnit.test('do not increase unread counter when receiving message with myself as author', async function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
var parent = this.createParent({
|
||||
@@ -204,9 +211,11 @@ QUnit.test('do not increase unread counter when receiving message with myself as
|
||||
});
|
||||
|
||||
// get channel instance to link to thread window
|
||||
await testUtils.nextTick();
|
||||
var channel = parent.call('mail_service', 'getChannel', 1);
|
||||
await testUtils.nextTick();
|
||||
channel.detach();
|
||||
|
||||
await testUtils.nextTick();
|
||||
var threadWindowHeaderText = $('.o_thread_window_header').text().replace(/\s/g, "");
|
||||
|
||||
assert.strictEqual(threadWindowHeaderText, "#general",
|
||||
@@ -226,6 +235,7 @@ QUnit.test('do not increase unread counter when receiving message with myself as
|
||||
var notification = [[false, 'mail.channel', 1], messageData];
|
||||
parent.call('bus_service', 'trigger', 'notification', [notification]);
|
||||
|
||||
await testUtils.nextTick();
|
||||
threadWindowHeaderText = $('.o_thread_window_header').text().replace(/\s/g, "");
|
||||
|
||||
assert.strictEqual(threadWindowHeaderText, "#general",
|
||||
@@ -236,7 +246,7 @@ QUnit.test('do not increase unread counter when receiving message with myself as
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('do not increment unread counter with focus on thread window', function (assert) {
|
||||
QUnit.test('do not increment unread counter with focus on thread window', async function (assert) {
|
||||
// 'hard' focus means that the user has clicked on the thread window in
|
||||
// order to set the focus on it.
|
||||
assert.expect(2);
|
||||
@@ -248,14 +258,17 @@ QUnit.test('do not increment unread counter with focus on thread window', functi
|
||||
});
|
||||
|
||||
// get channel instance to link to thread window
|
||||
await testUtils.nextTick();
|
||||
var channel = parent.call('mail_service', 'getChannel', 1);
|
||||
await testUtils.nextTick();
|
||||
channel.detach();
|
||||
await testUtils.nextTick();
|
||||
|
||||
assert.strictEqual(channel.getUnreadCounter(), 0,
|
||||
"thread should have unread counter to 0 initially");
|
||||
|
||||
// hard focus on thread window composer
|
||||
testUtils.dom.click($('.o_composer_text_field'));
|
||||
await testUtils.dom.click($('.o_composer_text_field'));
|
||||
|
||||
// simulate receiving message from someone else
|
||||
var messageData = {
|
||||
@@ -268,6 +281,7 @@ QUnit.test('do not increment unread counter with focus on thread window', functi
|
||||
};
|
||||
var notification = [[false, 'mail.channel', 1], messageData];
|
||||
parent.call('bus_service', 'trigger', 'notification', [notification]);
|
||||
await testUtils.nextTick();
|
||||
|
||||
assert.strictEqual(channel.getUnreadCounter(), 0,
|
||||
"thread should not have incremented its unread counter after receiving the message");
|
||||
@@ -275,7 +289,7 @@ QUnit.test('do not increment unread counter with focus on thread window', functi
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('do not mark as read the newly open thread window from received message', function (assert) {
|
||||
QUnit.test('do not mark as read the newly open thread window from received message', async function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
this.data['mail.channel'] = {
|
||||
@@ -315,7 +329,7 @@ QUnit.test('do not mark as read the newly open thread window from received messa
|
||||
if (args.method === 'channel_join_and_get_info') {
|
||||
this.data['mail.channel'].records[0].state = 'open';
|
||||
this.data['mail.channel'].records[0].is_minimized = true;
|
||||
return $.when(this.data['mail.channel'].records[0]);
|
||||
return Promise.resolve(this.data['mail.channel'].records[0]);
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
@@ -338,7 +352,7 @@ QUnit.test('do not mark as read the newly open thread window from received messa
|
||||
// a new message from a new channel.
|
||||
this.data['mail.channel'].records[0].message_unread_counter++;
|
||||
parent.call('bus_service', 'trigger', 'notification', [notification]);
|
||||
|
||||
await testUtils.nextTick();
|
||||
var $threadWindow = $('.o_thread_window');
|
||||
assert.strictEqual($threadWindow.length, 1,
|
||||
"a thread window should be open after receiving a new message on a new DM chat");
|
||||
@@ -347,14 +361,14 @@ QUnit.test('do not mark as read the newly open thread window from received messa
|
||||
assert.strictEqual($threadWindow.find('.o_thread_window_title').text().replace(/\s/g, ''), '#DM(1)',
|
||||
"open DM chat window should have one unread message");
|
||||
|
||||
testUtils.dom.click($threadWindow.find('.o_thread_composer'));
|
||||
await testUtils.dom.click($threadWindow.find('.o_thread_composer'));
|
||||
assert.strictEqual($threadWindow.find('.o_thread_window_title').text().replace(/\s/g, ''), '#DM',
|
||||
"open DM chat window should have message marked as read on composer focus");
|
||||
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('show document link of message linked to a document', function (assert) {
|
||||
QUnit.test('show document link of message linked to a document', async function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
this.data['mail.channel'] = {
|
||||
@@ -410,8 +424,11 @@ QUnit.test('show document link of message linked to a document', function (asser
|
||||
"no thread window should be open initially");
|
||||
|
||||
// get channel instance to link to thread window
|
||||
await testUtils.nextTick();
|
||||
var channel = parent.call('mail_service', 'getChannel', 2);
|
||||
await testUtils.nextTick();
|
||||
channel.detach();
|
||||
await testUtils.nextTick();
|
||||
|
||||
var $threadWindow = $('.o_thread_window');
|
||||
assert.strictEqual($threadWindow.length, 1,
|
||||
@@ -429,7 +446,7 @@ QUnit.test('show document link of message linked to a document', function (asser
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('do not autofocus chat window on receiving new direct message', function (assert) {
|
||||
QUnit.test('do not autofocus chat window on receiving new direct message', async function (assert) {
|
||||
// Receiving a message doesn't make other input loose focus
|
||||
assert.expect(3);
|
||||
|
||||
@@ -473,7 +490,7 @@ QUnit.test('do not autofocus chat window on receiving new direct message', funct
|
||||
}],
|
||||
};
|
||||
|
||||
var form = testUtils.createView({
|
||||
var form = await testUtils.createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
@@ -487,7 +504,7 @@ QUnit.test('do not autofocus chat window on receiving new direct message', funct
|
||||
},
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'channel_join_and_get_info') {
|
||||
return $.when(this.data['mail.channel'].records[0]);
|
||||
return Promise.resolve(this.data['mail.channel'].records[0]);
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
}
|
||||
@@ -512,7 +529,7 @@ QUnit.test('do not autofocus chat window on receiving new direct message', funct
|
||||
this.data['mail.message'].records.push(messageData);
|
||||
var notification = [[false, 'mail.channel', 2], messageData];
|
||||
form.call('bus_service', 'trigger', 'notification', [notification]);
|
||||
|
||||
await testUtils.nextTick();
|
||||
assert.ok($('.o_thread_window.o_in_home_menu').length,
|
||||
'Chat window is opened');
|
||||
|
||||
@@ -522,7 +539,7 @@ QUnit.test('do not autofocus chat window on receiving new direct message', funct
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('do not auto-focus chat window on receiving new message from new DM', function (assert) {
|
||||
QUnit.test('do not auto-focus chat window on receiving new message from new DM', async function (assert) {
|
||||
assert.expect(10);
|
||||
|
||||
var self = this;
|
||||
@@ -564,7 +581,7 @@ QUnit.test('do not auto-focus chat window on receiving new message from new DM',
|
||||
session: { partner_id: 3 },
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'channel_join_and_get_info') {
|
||||
return $.when(_.extend({}, self.data['mail.channel'].records[0], { info: 'join' }));
|
||||
return Promise.resolve(_.extend({}, self.data['mail.channel'].records[0], { info: 'join' }));
|
||||
}
|
||||
if (args.method === 'channel_minimize') {
|
||||
_.extend(self.data['mail.channel'].records[0], {
|
||||
@@ -594,6 +611,7 @@ QUnit.test('do not auto-focus chat window on receiving new message from new DM',
|
||||
this.data['mail.message'].records.push(messageData);
|
||||
var notification = [[false, 'mail.channel', 2], messageData];
|
||||
parent.call('bus_service', 'trigger', 'notification', [notification]);
|
||||
await testUtils.nextTick();
|
||||
|
||||
assert.strictEqual($('.o_thread_window').length, 1,
|
||||
"should have DM window open");
|
||||
@@ -610,6 +628,7 @@ QUnit.test('do not auto-focus chat window on receiving new message from new DM',
|
||||
});
|
||||
notification = [[false, 'res.partner', 3], dmInfo];
|
||||
parent.call('bus_service', 'trigger', 'notification', [notification]);
|
||||
await testUtils.nextTick();
|
||||
|
||||
assert.strictEqual($('.o_thread_window').length, 1,
|
||||
"should still have DM window open after receiving DM info from polling");
|
||||
@@ -621,6 +640,7 @@ QUnit.test('do not auto-focus chat window on receiving new message from new DM',
|
||||
// simulate receiving detached DM notification (cross-tab synchronization)
|
||||
notification = [[false, 'res.partner', 3], self.data['mail.channel'].records[0]];
|
||||
parent.call('bus_service', 'trigger', 'notification', [notification]);
|
||||
await testUtils.nextTick();
|
||||
|
||||
assert.strictEqual($('.o_thread_window').length, 1,
|
||||
"should still have DM open after receiving detached info from polling");
|
||||
@@ -632,7 +652,7 @@ QUnit.test('do not auto-focus chat window on receiving new message from new DM',
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('out-of-office status in thread window', function (assert) {
|
||||
QUnit.test('out-of-office status in thread window', async function (assert) {
|
||||
assert.expect(1);
|
||||
this.data = {
|
||||
'mail.message': {
|
||||
@@ -655,8 +675,13 @@ QUnit.test('out-of-office status in thread window', function (assert) {
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
await testUtils.nextTick();
|
||||
|
||||
// detach channel 1, so that it opens corresponding thread window.
|
||||
parent.call('mail_service', 'getChannel', 1).detach();
|
||||
var channel = parent.call('mail_service', 'getChannel', 1);
|
||||
await testUtils.nextTick();
|
||||
channel.detach();
|
||||
await testUtils.nextTick();
|
||||
|
||||
var $threadWindow = $('.o_thread_window');
|
||||
assert.containsOnce($threadWindow, '.o_out_of_office_text');
|
||||
@@ -664,7 +689,7 @@ QUnit.test('out-of-office status in thread window', function (assert) {
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('no out-of-office status in thread window', function (assert) {
|
||||
QUnit.test('no out-of-office status in thread window', async function (assert) {
|
||||
assert.expect(1);
|
||||
this.data = {
|
||||
'mail.message': {
|
||||
@@ -687,11 +712,17 @@ QUnit.test('no out-of-office status in thread window', function (assert) {
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
await testUtils.nextTick();
|
||||
|
||||
// detach channel 1, so that it opens corresponding thread window.
|
||||
parent.call('mail_service', 'getChannel', 1).detach();
|
||||
var channel = parent.call('mail_service', 'getChannel', 1);
|
||||
await testUtils.nextTick();
|
||||
channel.detach();
|
||||
await testUtils.nextTick();
|
||||
|
||||
var $threadWindow = $('.o_thread_window');
|
||||
assert.containsNone($threadWindow, '.o_out_of_office_text');
|
||||
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
|
||||
@@ -53,8 +53,8 @@ QUnit.module('Blank', {
|
||||
* functions end.
|
||||
*
|
||||
* @param {Object} params
|
||||
* @param {$.Deferred} params.selectDef
|
||||
* @param {$.Deferred} params.sourceDef
|
||||
* @param {Promise} params.selectDef
|
||||
* @param {Promise} params.sourceDef
|
||||
*/
|
||||
this.patchAutocomplete = function (params) {
|
||||
var selectDef = params.selectDef;
|
||||
@@ -87,7 +87,7 @@ QUnit.module('Blank', {
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test('basic rendering blank thread window', function (assert) {
|
||||
QUnit.test('basic rendering blank thread window', async function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
var parent = this.createParent({
|
||||
@@ -97,7 +97,7 @@ QUnit.test('basic rendering blank thread window', function (assert) {
|
||||
|
||||
// open blank thread window
|
||||
parent.call('mail_service', 'openBlankThreadWindow');
|
||||
|
||||
await testUtils.nextMicrotaskTick();
|
||||
assert.strictEqual($('.o_thread_window').length, 1,
|
||||
"should have a thread window open");
|
||||
assert.strictEqual($('.o_thread_window_title').text().trim(),
|
||||
@@ -114,7 +114,7 @@ QUnit.test('basic rendering blank thread window', function (assert) {
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('close blank thread window', function (assert) {
|
||||
QUnit.test('close blank thread window', async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var parent = this.createParent({
|
||||
@@ -124,8 +124,9 @@ QUnit.test('close blank thread window', function (assert) {
|
||||
|
||||
// open blank thread window
|
||||
parent.call('mail_service', 'openBlankThreadWindow');
|
||||
await testUtils.nextMicrotaskTick();
|
||||
|
||||
testUtils.dom.click($('.o_thread_window_close'));
|
||||
await testUtils.dom.click($('.o_thread_window_close'));
|
||||
|
||||
assert.strictEqual($('.o_thread_window').length, 0,
|
||||
"blank thread window should be closed");
|
||||
@@ -133,10 +134,10 @@ QUnit.test('close blank thread window', function (assert) {
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('fold blank thread window', function (assert) {
|
||||
QUnit.test('fold blank thread window', async function (assert) {
|
||||
// This test requires full height of thread windows when they are open.
|
||||
// (e.g. 400px)
|
||||
assert.expect(2);
|
||||
assert.expect(3);
|
||||
|
||||
var parent = this.createParent({
|
||||
data: this.data,
|
||||
@@ -153,34 +154,37 @@ QUnit.test('fold blank thread window', function (assert) {
|
||||
|
||||
// Open blank thread window
|
||||
parent.call('mail_service', 'openBlankThreadWindow');
|
||||
await testUtils.nextTick();
|
||||
|
||||
assert.containsOnce(document.body, '.o_thread_window');
|
||||
assert.strictEqual($('.o_thread_window').css('height'), HEIGHT_OPEN,
|
||||
"blank thread window should be open");
|
||||
if ($('.o_thread_window').css('height') !== HEIGHT_OPEN) {
|
||||
console.warn('Assertion above may fail due to too narrow height of browser');
|
||||
}
|
||||
|
||||
testUtils.dom.click($('.o_thread_window_title'));
|
||||
await testUtils.dom.click($('.o_thread_window_title'));
|
||||
assert.strictEqual($('.o_thread_window').css('height'), HEIGHT_FOLDED,
|
||||
"blank thread window should be open");
|
||||
"blank thread window should be folded");
|
||||
|
||||
parent.destroy();
|
||||
testUtils.mock.unpatch(AbstractThreadWindow);
|
||||
});
|
||||
|
||||
QUnit.test('open new DM chat from blank thread window', function (assert) {
|
||||
QUnit.test('open new DM chat from blank thread window', async function (assert) {
|
||||
assert.expect(6);
|
||||
var done = assert.async();
|
||||
|
||||
var self = this;
|
||||
var selectDef = $.Deferred();
|
||||
var sourceDef = $.Deferred();
|
||||
var selectDef = testUtils.makeTestPromise();
|
||||
var sourceDef = testUtils.makeTestPromise();
|
||||
|
||||
this.patchAutocomplete({
|
||||
selectDef: selectDef,
|
||||
sourceDef: sourceDef,
|
||||
});
|
||||
|
||||
var def = $.Deferred();
|
||||
var def = testUtils.makeTestPromise();
|
||||
|
||||
this.data['res.partner'] = {
|
||||
fields: {},
|
||||
@@ -193,13 +197,13 @@ QUnit.test('open new DM chat from blank thread window', function (assert) {
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'im_search') {
|
||||
def.resolve();
|
||||
return $.when([
|
||||
return Promise.resolve([
|
||||
{ id: 1, name: 'DemoUser1' },
|
||||
{ id: 2, name: 'DemoUser2', }
|
||||
]);
|
||||
}
|
||||
if (args.method === 'channel_get_and_minimize') {
|
||||
return $.when({
|
||||
return Promise.resolve({
|
||||
channel_type: 'chat',
|
||||
direct_partner: [{ id: args.args[0][0], name: 'DemoUser1', im_status: '' }],
|
||||
id: 50,
|
||||
@@ -213,19 +217,20 @@ QUnit.test('open new DM chat from blank thread window', function (assert) {
|
||||
|
||||
// open blank thread window
|
||||
parent.call('mail_service', 'openBlankThreadWindow');
|
||||
await testUtils.nextMicrotaskTick();
|
||||
await testUtils.fields.editAndTrigger($('.o_thread_search_input input'), 'D', 'keydown');
|
||||
await testUtils.nextTick();
|
||||
await Promise.all([sourceDef, def]);
|
||||
await testUtils.nextTick();
|
||||
assert.strictEqual($('.ui-menu-item a').length, 2,
|
||||
"should suggest 2 partners for DM");
|
||||
assert.strictEqual($('.ui-menu-item a').eq(0).text(), "DemoUser1",
|
||||
"first suggestion should be 'DemoUser1'");
|
||||
assert.strictEqual($('.ui-menu-item a').eq(1).text(), "DemoUser2",
|
||||
"second suggestion should be 'DemoUser2'");
|
||||
|
||||
$('.o_thread_search_input input').val("D").trigger('keydown');
|
||||
|
||||
$.when(sourceDef, def).then(function () {
|
||||
assert.strictEqual($('.ui-menu-item a').length, 2,
|
||||
"should suggest 2 partners for DM");
|
||||
assert.strictEqual($('.ui-menu-item a').eq(0).text(), "DemoUser1",
|
||||
"first suggestion should be 'DemoUser1'");
|
||||
assert.strictEqual($('.ui-menu-item a').eq(1).text(), "DemoUser2",
|
||||
"second suggestion should be 'DemoUser2'");
|
||||
|
||||
testUtils.dom.click($('.ui-menu-item a').eq(0));
|
||||
});
|
||||
await testUtils.dom.clickFirst($('.ui-menu-item a'),{allowInvisible:true});
|
||||
await testUtils.nextTick();
|
||||
selectDef.then(function () {
|
||||
assert.strictEqual($('.o_thread_window').length, 1,
|
||||
"should be a single window");
|
||||
@@ -240,22 +245,22 @@ QUnit.test('open new DM chat from blank thread window', function (assert) {
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test('open already detached DM chat from blank thread window', function (assert) {
|
||||
QUnit.test('open already detached DM chat from blank thread window', async function (assert) {
|
||||
// when opening an already detach DM chat from the blank thread window,
|
||||
// the blank thread window should disappear
|
||||
assert.expect(6);
|
||||
var done = assert.async();
|
||||
|
||||
var self = this;
|
||||
var selectDef = $.Deferred();
|
||||
var sourceDef = $.Deferred();
|
||||
var selectDef = testUtils.makeTestPromise();
|
||||
var sourceDef = testUtils.makeTestPromise();
|
||||
|
||||
this.patchAutocomplete({
|
||||
selectDef: selectDef,
|
||||
sourceDef: sourceDef,
|
||||
});
|
||||
|
||||
var def = $.Deferred();
|
||||
var def = testUtils.makeTestPromise();
|
||||
|
||||
this.data['res.partner'] = {
|
||||
fields: {},
|
||||
@@ -275,7 +280,7 @@ QUnit.test('open already detached DM chat from blank thread window', function (a
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'im_search') {
|
||||
def.resolve();
|
||||
return $.when([
|
||||
return Promise.resolve([
|
||||
{ id: 1, name: 'DemoUser1' },
|
||||
]);
|
||||
}
|
||||
@@ -283,6 +288,7 @@ QUnit.test('open already detached DM chat from blank thread window', function (a
|
||||
},
|
||||
});
|
||||
|
||||
await testUtils.nextTick();
|
||||
assert.strictEqual($('.o_thread_window').length, 1,
|
||||
"should be a single window");
|
||||
assert.strictEqual($('.o_thread_window_title').text().trim(), "DemoUser1",
|
||||
@@ -292,15 +298,16 @@ QUnit.test('open already detached DM chat from blank thread window', function (a
|
||||
|
||||
// open blank thread window
|
||||
parent.call('mail_service', 'openBlankThreadWindow');
|
||||
|
||||
await testUtils.nextMicrotaskTick();
|
||||
assert.strictEqual($('.o_thread_window').length, 2,
|
||||
"should have two thread windows open");
|
||||
await testUtils.fields.editAndTrigger($('.o_thread_search_input input'), 'D', 'keydown');
|
||||
|
||||
$('.o_thread_search_input input').val("D").trigger('keydown');
|
||||
|
||||
$.when(sourceDef, def).then(function () {
|
||||
testUtils.dom.click($('.ui-menu-item a').eq(0));
|
||||
});
|
||||
await Promise.all([sourceDef, def]);
|
||||
await testUtils.nextTick();
|
||||
await testUtils.dom.click($('.ui-menu-item a'),{allowInvisible:true});
|
||||
await testUtils.nextTick();
|
||||
selectDef.then(function () {
|
||||
assert.strictEqual($('.o_thread_window').length, 1,
|
||||
"should now have a single thread window open");
|
||||
|
||||
@@ -48,12 +48,15 @@ QUnit.module('Hidden', {
|
||||
};
|
||||
},
|
||||
afterEach: function () {
|
||||
// remove thread window dropup appended by mail service
|
||||
var $target = $(this.services.mail_service.prototype.THREAD_WINDOW_APPENDTO);
|
||||
$target.find('.o_thread_window_dropdown').remove();
|
||||
// reset thread window append to body
|
||||
this.services.mail_service.prototype.THREAD_WINDOW_APPENDTO = 'body';
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test('hidden thread windows dropdown when not enough horizontal space (version 1)', function (assert) {
|
||||
QUnit.test('hidden thread windows dropdown when not enough horizontal space (version 1)', async function (assert) {
|
||||
// This test has hard-set global width, so that it does not depend on
|
||||
// the width of the screen: at most 2 thread windows visible at the
|
||||
// same time, and additional thread windows are in hidden while and
|
||||
@@ -87,9 +90,10 @@ QUnit.test('hidden thread windows dropdown when not enough horizontal space (ver
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
|
||||
await testUtils.nextTick();
|
||||
parent.call('mail_service', 'getChannel', 0).detach();
|
||||
parent.call('mail_service', 'getChannel', 1).detach();
|
||||
await testUtils.nextTick();
|
||||
|
||||
var $visibleThreadWindows = $('.o_thread_window:not(.o_thread_window_dropdown, .o_hidden)');
|
||||
|
||||
@@ -106,6 +110,7 @@ QUnit.test('hidden thread windows dropdown when not enough horizontal space (ver
|
||||
|
||||
// detach a channel so that it exceeds available slots
|
||||
parent.call('mail_service', 'getChannel', 2).detach();
|
||||
await testUtils.nextTick();
|
||||
// update list of visible thread windows
|
||||
$visibleThreadWindows = $('.o_thread_window:not(.o_thread_window_dropdown, .o_hidden)');
|
||||
|
||||
@@ -131,7 +136,7 @@ QUnit.test('hidden thread windows dropdown when not enough horizontal space (ver
|
||||
testUtils.mock.unpatch(this.services.mail_service);
|
||||
});
|
||||
|
||||
QUnit.test('hidden thread windows dropdown when not enough horizontal space (version 2)', function (assert) {
|
||||
QUnit.test('hidden thread windows dropdown when not enough horizontal space (version 2)', async function (assert) {
|
||||
// This is almost the same test as the one before, except there are
|
||||
// at most 3 thread windows visible, and 2 thread windows are visible
|
||||
// when it shows the 'hidden thread window' button.
|
||||
@@ -171,10 +176,11 @@ QUnit.test('hidden thread windows dropdown when not enough horizontal space (ver
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
|
||||
await testUtils.nextTick();
|
||||
parent.call('mail_service', 'getChannel', 0).detach();
|
||||
parent.call('mail_service', 'getChannel', 1).detach();
|
||||
parent.call('mail_service', 'getChannel', 2).detach();
|
||||
await testUtils.nextTick();
|
||||
|
||||
var $visibleThreadWindows = $('.o_thread_window:not(.o_thread_window_dropdown, .o_hidden)');
|
||||
|
||||
@@ -193,6 +199,7 @@ QUnit.test('hidden thread windows dropdown when not enough horizontal space (ver
|
||||
|
||||
// detach a channel so that it exceeds available slots
|
||||
parent.call('mail_service', 'getChannel', 3).detach();
|
||||
await testUtils.nextTick();
|
||||
// update list of visible thread windows
|
||||
$visibleThreadWindows = $('.o_thread_window:not(.o_thread_window_dropdown, .o_hidden)');
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ QUnit.module('Moderation', {
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test('moderator: moderated channel with pending moderation message', function (assert) {
|
||||
QUnit.test('moderator: moderated channel with pending moderation message', async function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
this.data.initMessaging = {
|
||||
@@ -114,9 +114,10 @@ QUnit.test('moderator: moderated channel with pending moderation message', funct
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
|
||||
await testUtils.nextTick();
|
||||
// detach channel 1, so that it opens corresponding thread window.
|
||||
parent.call('mail_service', 'getChannel', 1).detach();
|
||||
await testUtils.nextTick();
|
||||
|
||||
assert.strictEqual($('.o_thread_message ').length, 1,
|
||||
"should display a message in the thread window");
|
||||
|
||||
@@ -40,7 +40,7 @@ QUnit.module('Typing', {
|
||||
* @param {integer} params.partnerID
|
||||
* @param {Widget} params.widget a widget that can call the bus_service
|
||||
*/
|
||||
this.simulateIsTyping = function (params) {
|
||||
this.simulateIsTyping = async function (params) {
|
||||
var typingData = {
|
||||
info: 'typing_status',
|
||||
partner_id: params.partnerID,
|
||||
@@ -48,6 +48,7 @@ QUnit.module('Typing', {
|
||||
};
|
||||
var notification = [[false, 'mail.channel', params.channelID], typingData];
|
||||
params.widget.call('bus_service', 'trigger', 'notification', [notification]);
|
||||
await testUtils.nextMicrotaskTick();
|
||||
};
|
||||
|
||||
this.createParent = function (params) {
|
||||
@@ -72,7 +73,7 @@ QUnit.module('Typing', {
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test('receive typing notification', function (assert) {
|
||||
QUnit.test('receive typing notification', async function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
var parent = this.createParent({
|
||||
@@ -82,22 +83,24 @@ QUnit.test('receive typing notification', function (assert) {
|
||||
// when receiving an 'is typing' notification, fetch the list of
|
||||
// members of this channel if we haven't done yet.
|
||||
if (args.method === 'channel_fetch_listeners') {
|
||||
return $.when([
|
||||
return Promise.resolve([
|
||||
{ id: 42, name: "Someone" },
|
||||
]);
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
await testUtils.nextTick();
|
||||
|
||||
// detach channel 1, so that it opens corresponding thread window.
|
||||
parent.call('mail_service', 'getChannel', 1).detach();
|
||||
await testUtils.nextTick();
|
||||
|
||||
var $threadWindow = $('.o_thread_window');
|
||||
assert.containsNone($threadWindow, '.o_mail_thread_typing_icon',
|
||||
"should not display an icon that someone is typing something on this thread");
|
||||
|
||||
this.simulateIsTyping({
|
||||
await this.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: 42,
|
||||
@@ -110,7 +113,7 @@ QUnit.test('receive typing notification', function (assert) {
|
||||
"Someone is typing...",
|
||||
"should display someone is typing something on hover of this icon");
|
||||
|
||||
this.simulateIsTyping({
|
||||
await this.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: false,
|
||||
partnerID: 42,
|
||||
|
||||
@@ -7,7 +7,7 @@ var createDebugManager = testUtils.createDebugManager;
|
||||
|
||||
QUnit.module('Mail DebugManager', {}, function () {
|
||||
|
||||
QUnit.test("Manage Messages", function (assert) {
|
||||
QUnit.test("Manage Messages", async function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
var debugManager = createDebugManager({
|
||||
@@ -47,15 +47,16 @@ QUnit.module('Mail DebugManager', {}, function () {
|
||||
},
|
||||
modelName: 'testModel',
|
||||
};
|
||||
debugManager.update('action', action, view);
|
||||
await testUtils.nextTick();
|
||||
await debugManager.update('action', action, view);
|
||||
|
||||
var $messageMenu = debugManager.$('a[data-action=getMailMessages]');
|
||||
assert.strictEqual($messageMenu.length, 1, "should have Manage Message menu item");
|
||||
assert.strictEqual($messageMenu.text().trim(), "Manage Messages",
|
||||
"should have correct menu item text");
|
||||
|
||||
testUtils.dom.click(debugManager.$('> a')); // open dropdown
|
||||
testUtils.dom.click($messageMenu);
|
||||
await testUtils.dom.click(debugManager.$('> a')); // open dropdown
|
||||
await testUtils.dom.click($messageMenu);
|
||||
|
||||
debugManager.destroy();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user