[IMP] mail: activity keyboard navigation improvement

PURPOSE

Improve some mail activity issues regarding keyboard navigation.

SPECIFICATIONS

When done an activity using the record list view, allowing user ENTER key
support on "Done" or "Done and Schedule Next" button to post feedback and
mark the activity as done.

Task-2528109

closes odoo/odoo#82879

Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
This commit is contained in:
Ipsita Borisagar
2022-05-18 11:59:48 +02:00
parent 814659b73d
commit c8db947024
3 changed files with 169 additions and 0 deletions
+26
View File
@@ -377,6 +377,7 @@ var BasicActivity = AbstractField.extend({
this.$('.o_activity_selected').removeClass('o_activity_selected');
$actLi.toggleClass('o_activity_selected');
$panel.collapse('toggle');
$panel.find('#activity_feedback').focus();
} else if (!$markDoneBtn.data('bs.popover')) {
$markDoneBtn.popover({
@@ -418,6 +419,11 @@ var BasicActivity = AbstractField.extend({
_onMarkActivityDoneActions: function ($btn, $form, activityID) {
var self = this;
$form.find('#activity_feedback').val(self._draftFeedback[activityID]);
$form.on('keydown', '#activity_feedback', function (ev) {
if (ev.key === 'Enter') {
ev.stopPropagation(); // Prevent list view actions
}
});
$form.on('click', '.o_activity_popover_done', function (ev) {
ev.stopPropagation();
self._markActivityDone({
@@ -425,6 +431,16 @@ var BasicActivity = AbstractField.extend({
feedback: $form.find('#activity_feedback').val(),
});
});
$form.on('keydown', '.o_activity_popover_done', function (ev) {
if (ev.key === 'Enter') {
ev.stopPropagation(); // Prevent list view actions
ev.preventDefault();
self._markActivityDone({
activityID,
feedback: $form.find('#activity_feedback').val(),
});
}
});
$form.on('click', '.o_activity_popover_done_next', function (ev) {
ev.stopPropagation();
self._markActivityDoneAndScheduleNext({
@@ -432,6 +448,16 @@ var BasicActivity = AbstractField.extend({
feedback: $form.find('#activity_feedback').val(),
});
});
$form.on('keydown', '.o_activity_popover_done_next', function (ev) {
if (ev.key === 'Enter') {
ev.stopPropagation(); // Prevent list view actions
ev.preventDefault();
self._markActivityDoneAndScheduleNext({
activityID,
feedback: $form.find('#activity_feedback').val(),
});
}
});
$form.on('click', '.o_activity_popover_discard', function (ev) {
ev.stopPropagation();
if ($btn.data('bs.popover')) {
@@ -154,6 +154,14 @@ MockServer.include({
return;
}
// mail.activity methods
if (args.model === 'mail.activity' && args.method === 'action_feedback') {
const ids = args.args[0];
return this._mockMailActivityActionFeedback(ids);
}
if (args.model === 'mail.activity' && args.method === 'action_feedback_schedule_next') {
const ids = args.args[0];
return this._mockMailActivityActionFeedbackScheduleNext(ids);
}
if (args.model === 'mail.activity' && args.method === 'activity_format') {
const ids = args.args[0];
return this._mockMailActivityActivityFormat(ids);
@@ -635,6 +643,47 @@ MockServer.include({
return res;
});
},
/**
* Simulates `_action_done` on `mail.activity`.
*
* @private
* @param {string} model
* @param {integer[]} ids
* @returns {Object}
*/
_mockMailActivityActionDone(ids) {
const activities = this.getRecords('mail.activity', [['id', 'in', ids]]);
this._mockUnlink('mail.activity', [activities.map(activity => activity.id)]);
},
/**
* Simulates `action_feedback` on `mail.activity`.
*
* @private
* @param {string} model
* @param {integer[]} ids
* @returns {Object}
*/
_mockMailActivityActionFeedback(ids) {
this._mockMailActivityActionDone(ids);
},
/**
* Simulates `action_feedback_schedule_next` on `mail.activity`.
*
* @private
* @param {string} model
* @param {integer[]} ids
* @returns {Object}
*/
_mockMailActivityActionFeedbackScheduleNext(ids) {
this._mockMailActivityActionDone(ids);
return {
name: 'Schedule an Activity',
view_mode: 'form',
res_model: 'mail.activity',
views: [[false, 'form']],
type: 'ir.actions.act_window',
}
},
/**
* Simulates `get_activity_data` on `mail.activity`.
*
@@ -252,6 +252,100 @@ QUnit.test('list activity exception widget with activity', async function (asser
"there is an exception on a record");
});
QUnit.test('list activity widget: done the activity with "ENTER" keyboard shortcut', async function (assert) {
assert.expect(1);
const pyEnv = await startServer();
const mailActivityTypeId1 = pyEnv['mail.activity.type'].create();
const mailActivityId1 = pyEnv['mail.activity'].create([
{
display_name: "Call with Al",
date_deadline: moment().format("YYYY-MM-DD"), // now
can_write: true,
state: "today",
user_id: pyEnv.currentUserId,
create_uid: pyEnv.currentUserId,
activity_type_id: mailActivityTypeId1,
}
]);
pyEnv['res.users'].write([pyEnv.currentUserId], {
activity_ids: [mailActivityId1],
activity_state: 'today',
activity_summary: 'Call with Al',
activity_type_id: mailActivityTypeId1,
});
const { target: list } = await start({
hasView: true,
View: ListView,
model: 'res.users',
arch: `
<list>
<field name="activity_ids" widget="list_activity"/>
</list>`,
});
await testUtils.dom.click(list.querySelector('.o_activity_btn span'));
await testUtils.dom.click(list.querySelector('.o_mark_as_done'));
pyEnv['res.users'].write([pyEnv.currentUserId], {
activity_state: '',
});
await testUtils.dom.triggerEvent(
document.querySelector('.o_activity_popover_done'),
'keydown',
{ key: 'Enter' },
);
assert.containsOnce(list, '.o_mail_activity .o_activity_color_default');
});
QUnit.test('list activity widget: done and schedule the next activity with "ENTER" keyboard shortcut', async function (assert) {
assert.expect(1);
const pyEnv = await startServer();
const mailActivityTypeId1 = pyEnv['mail.activity.type'].create();
const mailActivityId1 = pyEnv['mail.activity'].create([
{
display_name: "Call with Al",
date_deadline: moment().format("YYYY-MM-DD"), // now
can_write: true,
state: "today",
user_id: pyEnv.currentUserId,
create_uid: pyEnv.currentUserId,
activity_type_id: mailActivityTypeId1,
}
]);
pyEnv['res.users'].write([pyEnv.currentUserId], {
activity_ids: [mailActivityId1],
activity_state: 'today',
activity_summary: 'Call with Al',
activity_type_id: mailActivityTypeId1,
});
const { target: list } = await start({
hasView: true,
View: ListView,
model: 'res.users',
arch: `
<list>
<field name="activity_ids" widget="list_activity"/>
</list>`,
intercepts: {
do_action: function (ev) {
assert.strictEqual(ev.data.action.name, "Schedule an Activity", 'should do a do_action with correct parameters');
},
},
});
await testUtils.dom.click(list.querySelector('.o_activity_btn span'));
await testUtils.dom.click(list.querySelector('.o_mark_as_done'));
await testUtils.dom.triggerEvent(
document.querySelector('.o_activity_popover_done_next'),
'keydown',
{ key: 'Enter' },
);
});
QUnit.module('FieldMany2ManyTagsEmail');
QUnit.test('fieldmany2many tags email (edition)', async function (assert) {