From fd02fec8d8d0dc73d2403cef540922dc25534e93 Mon Sep 17 00:00:00 2001 From: RomainLibert Date: Thu, 9 Aug 2018 14:22:00 +0200 Subject: [PATCH] [IMP] mail: add feedback option to kanban activities In the kanban view, there was no possibility to add a feedback when closing an activity this commit adds the same popover as the one we have in the form view. This commit also add the templates to this popover with the possible to directly send the template or open the composer. Task #1870662 Closes #26280 --- addons/mail/static/src/js/activity.js | 110 +++++++++++++++++- .../mail/static/src/scss/mail_activity.scss | 13 ++- .../static/src/xml/web_kanban_activity.xml | 15 ++- addons/mail/static/tests/chatter_tests.js | 58 +++++++++ 4 files changed, 191 insertions(+), 5 deletions(-) diff --git a/addons/mail/static/src/js/activity.js b/addons/mail/static/src/js/activity.js index 1221cab2f52..acd15cbef20 100644 --- a/addons/mail/static/src/js/activity.js +++ b/addons/mail/static/src/js/activity.js @@ -447,6 +447,8 @@ var KanbanActivity = AbstractActivityField.extend({ 'show.bs.dropdown': '_onDropdownShow', 'click .o_schedule_activity': '_onScheduleActivity', 'click .o_mark_as_done': '_onMarkActivityDone', + 'click .o_activity_template_preview': '_onPreviewMailTemplate', + 'click .o_activity_template_send': '_onSendMailTemplate', }, /** @@ -460,6 +462,7 @@ var KanbanActivity = AbstractActivityField.extend({ }); this.selection = selection; this._setState(record); + this._draftFeedback = {}; }, //------------------------------------------------------------ @@ -522,6 +525,19 @@ var KanbanActivity = AbstractActivityField.extend({ }, + //------------------------------------------------------------ + // Public + //------------------------------------------------------------ + + /** + * @param {integer} previousActivityTypeID + * @return {$.Promise} + */ + scheduleActivity: function (previousActivityTypeID) { + var callback = this._reload.bind(this, { activity: true, thread: true }); + return this._scheduleActivity(false, previousActivityTypeID, callback); + }, + //------------------------------------------------------------ // Handlers //------------------------------------------------------------ @@ -538,8 +554,61 @@ var KanbanActivity = AbstractActivityField.extend({ */ _onMarkActivityDone: function (ev) { ev.stopPropagation(); - var activityID = $(ev.currentTarget).data('activity-id'); - this._sendActivityFeedback(activityID).then(this._reload.bind(this)); + var self = this; + var $popoverElement = $(ev.currentTarget); + var activityID = $popoverElement.data('activity-id'); + var previousActivityTypeID = $popoverElement.data('previous-activity-type-id'); + + if (!$popoverElement.data('bs.popover')) { + $popoverElement.popover({ + template: $(Popover.Default.template).addClass('o_mail_activity_feedback')[0].outerHTML, // Ugly but cannot find another way + container: $popoverElement.parent(), // FIXME Ugly and should probably be in the body as by default but form view should handle destroying popovers + title : _t("Feedback"), + html: true, + trigger:'click', + content : function () { + var $popover = $(QWeb.render('mail.activity_feedback_form', { 'previous_activity_type_id': previousActivityTypeID })); + $popover.find('#activity_feedback').val(self._draftFeedback[activityID]); + $popover.on('click', function (ev) { + ev.stopPropagation(); + }); + $popover.on('click', '.o_activity_popover_done', function (ev) { + ev.stopPropagation(); + self._markActivityDone({ + activityID: activityID, + feedback: _.escape($popover.find('#activity_feedback').val()), + }); + }); + $popover.on('click', '.o_activity_popover_done_next', function (ev) { + ev.stopPropagation(); + self._markActivityDoneAndScheduleNext({ + activityID: activityID, + activityTypeID: $popoverElement.data('previous-activity-type-id'), + feedback: _.escape($popover.find('#activity_feedback').val()), + }); + }); + $popover.on('click', '.o_activity_popover_discard', function (ev) { + ev.stopPropagation(); + $popoverElement.popover('hide'); + }); + return $popover; + }, + }).on('shown.bs.popover', function () { + var $popover = $($(this).data("bs.popover").tip); + $(".o_mail_activity_feedback.popover").not($popover).popover("hide"); + $popover.addClass('o_mail_activity_feedback').attr('tabindex', 0); + $popover.find('#activity_feedback').focus(); + $popover.off('focusout'); + $popover.focusout(function (e) { + // outside click of popover hide the popover + // e.relatedTarget is the element receiving the focus + if (!$popover.is(e.relatedTarget) && !$popover.find(e.relatedTarget).length) { + self._draftFeedback[activityID] = $popover.find('#activity_feedback').val(); + $popover.popover('hide'); + } + }); + }).popover('show'); + } }, /** * @private @@ -550,6 +619,43 @@ var KanbanActivity = AbstractActivityField.extend({ var activityID = $(ev.currentTarget).data('activity-id') || false; return this._scheduleActivity(activityID, false, this._reload.bind(this)); }, + /** + * @private + * @param {MouseEvent} ev + */ + _onPreviewMailTemplate: function (ev) { + ev.stopPropagation(); + var templateID = $(ev.target).data('template-id'); + var action = { + name: _t('Compose Email'), + type: 'ir.actions.act_window', + res_model: 'mail.compose.message', + views: [[false, 'form']], + target: 'new', + context: { + default_res_id: this.res_id, + default_model: this.model, + default_use_template: true, + default_template_id: templateID, + force_email: true, + }, + }; + return this.do_action(action, { on_close: function(){}}); + }, + /** + * @private + * @param {MouseEvent} ev + */ + _onSendMailTemplate: function (ev) { + ev.stopPropagation(); + var templateID = $(ev.target).data('template-id'); + return this._rpc({ + model: this.model, + method: 'activity_send_mail', + args: [[this.res_id], templateID], + }) + .then(this._reload.bind(this, {activity: true, thread: true, followers: true})); + }, }); field_registry diff --git a/addons/mail/static/src/scss/mail_activity.scss b/addons/mail/static/src/scss/mail_activity.scss index 78fa281cb66..7fbe0e89c82 100644 --- a/addons/mail/static/src/scss/mail_activity.scss +++ b/addons/mail/static/src/scss/mail_activity.scss @@ -164,8 +164,18 @@ } } + .o_activity_template_preview,.o_activity_template_send { + font-weight: bold; + color: $o-brand-primary; + cursor: pointer; + &:hover:not(.active) { + color: darken($o-brand-primary, 15%); + border-color: darken($o-brand-primary, 15%); + } + } + div.o_activity { - width: 290px; + min-width: 290px; padding: 0px 0px; > :last-child { @@ -201,7 +211,6 @@ width: 85%; padding: 0px 5px 0px 10px; white-space: nowrap; - overflow: hidden; text-overflow: ellipsis; } } diff --git a/addons/mail/static/src/xml/web_kanban_activity.xml b/addons/mail/static/src/xml/web_kanban_activity.xml index cfa88d90bb2..f61d22d569e 100644 --- a/addons/mail/static/src/xml/web_kanban_activity.xml +++ b/addons/mail/static/src/xml/web_kanban_activity.xml @@ -38,6 +38,19 @@
+
+ + +
+ + : + Preview + or + Send Now +
+
+
+
@@ -45,7 +58,7 @@
- +
diff --git a/addons/mail/static/tests/chatter_tests.js b/addons/mail/static/tests/chatter_tests.js index e6a770c0f65..047a49b38c3 100644 --- a/addons/mail/static/tests/chatter_tests.js +++ b/addons/mail/static/tests/chatter_tests.js @@ -409,6 +409,7 @@ QUnit.test('kanban activity widget with an activity', function (assert) { // mark activity as done $record.find('.o_mark_as_done').click(); + $record.find('.o_activity_popover_done').click(); $record = kanban.$('.o_kanban_record').first(); // the record widget has been reset assert.strictEqual(rpcCount, 5, 'should have done an RPC to mark activity as done, and a read'); assert.ok($record.find('.o_mail_activity .o_activity_color_default:not(.o_activity_color_today)').length, @@ -420,6 +421,63 @@ QUnit.test('kanban activity widget with an activity', function (assert) { kanban.destroy(); }); +QUnit.test('kanban activity widget popover test', function (assert) { + assert.expect(3); + + this.data.partner.records[0].activity_ids = [1]; + this.data.partner.records[0].activity_state = 'today'; + this.data['mail.activity'].records = [{ + id: 1, + display_name: "An activity", + date_deadline: moment().format("YYYY-MM-DD"), // now + state: "today", + user_id: 2, + create_user_id: 2, + activity_type_id: 1, + }]; + var rpcCount = 0; + var kanban = createView({ + View: KanbanView, + model: 'partner', + data: this.data, + arch: '' + + '' + + '' + + '
' + + '
' + + '
', + mockRPC: function (route, args) { + if (route === '/web/dataset/call_kw/mail.activity/action_feedback') { + rpcCount++; + + var current_ids = this.data.partner.records[0].activity_ids; + var done_ids = args.args[0]; + this.data.partner.records[0].activity_ids = _.difference(current_ids, done_ids); + this.data.partner.records[0].activity_state = false; + return $.when(); + } + return this._super(route, args); + }, + }); + + var $record = kanban.$('.o_kanban_record').first(); + + $record.find('.o_activity_btn').click(); + + // Click on button and see popover no RPC call + $record.find('.o_mark_as_done').click(); + assert.equal(rpcCount, 0, ""); + // Click on discard no RPC call + $record.find('.o_activity_popover_discard').click(); + assert.equal(rpcCount, 0, ""); + // Click on button and then on done and schedule next + // RPC call + $record.find('.o_activity_popover_done_next').click(); + assert.equal(rpcCount, 1, ""); + + kanban.destroy(); +}); + QUnit.test('chatter: post, receive and star messages', function (assert) { var done = assert.async(); assert.expect(27);