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);