- Planned
+ Planned
diff --git a/addons/mail/static/src/backend_components/kanban_field_activity_view/kanban_field_activity_view_container.js b/addons/mail/static/src/backend_components/kanban_field_activity_view/kanban_field_activity_view_container.js
index 0fc4e00b7c0..1ce89575dc3 100644
--- a/addons/mail/static/src/backend_components/kanban_field_activity_view/kanban_field_activity_view_container.js
+++ b/addons/mail/static/src/backend_components/kanban_field_activity_view/kanban_field_activity_view_container.js
@@ -59,7 +59,7 @@ export class KanbanFieldActivityViewContainer extends Component {
const kanbanFieldActivityView = messaging.models['KanbanFieldActivityView'].insert({
id: this.kanbanFieldActivityViewId,
thread: {
- activities: this.props.value.records.map(activityData => {
+ activities: props.value.records.map(activityData => {
return {
id: activityData.resId,
};
diff --git a/addons/mail/static/src/backend_components/list_field_activity_view/list_field_activity_view_container.js b/addons/mail/static/src/backend_components/list_field_activity_view/list_field_activity_view_container.js
index f137bb34665..4c91f4d555a 100644
--- a/addons/mail/static/src/backend_components/list_field_activity_view/list_field_activity_view_container.js
+++ b/addons/mail/static/src/backend_components/list_field_activity_view/list_field_activity_view_container.js
@@ -59,7 +59,7 @@ export class ListFieldActivityViewContainer extends Component {
const listFieldActivityView = messaging.models['ListFieldActivityView'].insert({
id: this.listFieldActivityViewId,
thread: {
- activities: this.props.value.records.map(activityData => {
+ activities: props.value.records.map(activityData => {
return {
id: activityData.resId,
};
diff --git a/addons/mail/static/src/js/activity.js b/addons/mail/static/src/js/activity.js
index d5c9091628b..f60fc3f9678 100644
--- a/addons/mail/static/src/js/activity.js
+++ b/addons/mail/static/src/js/activity.js
@@ -45,7 +45,6 @@ const KanbanActivity = AbstractField.extend({
this.selection[key] = value;
}
this.defaultActivityType = options.activityType;
- this.isActivityViewCell = options.isActivityViewCell;
},
async willStart() {
await this._super();
@@ -379,38 +378,17 @@ const KanbanActivity = AbstractField.extend({
* @private
*/
_render() {
- if (this.isActivityViewCell) {
- // replace clock by closest deadline
- const $date = $('');
- const date = moment(this.record.data.closest_deadline).toDate();
- // To remove year only if current year
- if (moment().year() === moment(date).year()) {
- $date.text(date.toLocaleDateString(moment().locale(), {
- day: 'numeric', month: 'short'
- }));
- } else {
- $date.text(moment(date).format('ll'));
- }
- this.$('a').html($date);
- if (this.record.data.activity_ids.res_ids.length > 1) {
- this.$('a').append($('', {
- class: 'badge bg-light rounded-pill border-0 ' + this.record.data.activity_state,
- text: this.record.data.activity_ids.res_ids.length,
- }));
- }
+ // span classes need to be updated manually because the template cannot
+ // be re-rendered eaasily (because of the dropdown state)
+ const spanClasses = ['fa', 'fa-lg', 'fa-fw'];
+ spanClasses.push('o_activity_color_' + (this.record.data.activity_state || 'default'));
+ if (this.recordData.activity_exception_decoration) {
+ spanClasses.push('text-' + this.recordData.activity_exception_decoration);
+ spanClasses.push(this.recordData.activity_exception_icon);
} else {
- // span classes need to be updated manually because the template cannot
- // be re-rendered eaasily (because of the dropdown state)
- const spanClasses = ['fa', 'fa-lg', 'fa-fw'];
- spanClasses.push('o_activity_color_' + (this.record.data.activity_state || 'default'));
- if (this.recordData.activity_exception_decoration) {
- spanClasses.push('text-' + this.recordData.activity_exception_decoration);
- spanClasses.push(this.recordData.activity_exception_icon);
- } else {
- spanClasses.push('fa-clock-o');
- }
- this.$('.o_activity_btn > span').removeClass().addClass(spanClasses.join(' '));
+ spanClasses.push('fa-clock-o');
}
+ this.$('.o_activity_btn > span').removeClass().addClass(spanClasses.join(' '));
if (this.$el.hasClass('show')) {
// note: this part of the rendering might be asynchronous
this._renderDropdown();
diff --git a/addons/mail/static/src/js/views/activity/activity_controller.js b/addons/mail/static/src/js/views/activity/activity_controller.js
index 7e249476fc5..8b5506bde8e 100644
--- a/addons/mail/static/src/js/views/activity/activity_controller.js
+++ b/addons/mail/static/src/js/views/activity/activity_controller.js
@@ -14,6 +14,7 @@ var _t = core._t;
var ActivityController = BasicController.extend({
custom_events: _.extend({}, BasicController.prototype.custom_events, {
empty_cell_clicked: '_onEmptyCell',
+ reload_data: '_onReloadData',
send_mail_template: '_onSendMailTemplate',
schedule_activity: '_onScheduleActivity',
}),
@@ -53,6 +54,12 @@ var ActivityController = BasicController.extend({
// Handlers
//--------------------------------------------------------------------------
+ /**
+ * @private
+ */
+ _onReloadData() {
+ this.trigger_up('reload');
+ },
/**
* @private
*/
diff --git a/addons/mail/static/src/js/views/activity/activity_model.js b/addons/mail/static/src/js/views/activity/activity_model.js
index 715329e1228..8b07fa48b2e 100644
--- a/addons/mail/static/src/js/views/activity/activity_model.js
+++ b/addons/mail/static/src/js/views/activity/activity_model.js
@@ -20,44 +20,10 @@ const ActivityModel = BasicModel.extend({
__get: function () {
var result = this._super.apply(this, arguments);
if (result && result.model === this.modelName && result.type === 'list') {
- _.extend(result, this.additionalData, {getKanbanActivityData: this.getKanbanActivityData});
+ _.extend(result, this.additionalData);
}
return result;
},
- /**
- * @param {Object} activityGroup
- * @param {integer} resId
- * @returns {Object}
- */
- getKanbanActivityData(activityGroup, resId) {
- return {
- data: {
- activity_ids: {
- model: 'mail.activity',
- res_ids: activityGroup.ids,
- },
- activity_state: activityGroup.state,
- closest_deadline: activityGroup.o_closest_deadline,
- },
- fields: {
- activity_ids: {},
- activity_state: {
- selection: [
- ['overdue', "Overdue"],
- ['today', "Today"],
- ['planned', "Planned"],
- ],
- },
- },
- fieldsInfo: {},
- model: this.model,
- type: 'record',
- res_id: resId,
- getContext: function () {
- return {};
- },
- };
- },
/**
* @override
* @param {Array[]} params.domain
diff --git a/addons/mail/static/src/js/views/activity/activity_renderer.js b/addons/mail/static/src/js/views/activity/activity_renderer.js
index 01e0d622c8a..8411c9e56b9 100644
--- a/addons/mail/static/src/js/views/activity/activity_renderer.js
+++ b/addons/mail/static/src/js/views/activity/activity_renderer.js
@@ -1,10 +1,10 @@
/** @odoo-module **/
import ActivityRecord from '@mail/js/views/activity/activity_record';
+import { ActivityCellViewContainer } from '@mail/backend_components/activity_cell_view/activity_cell_view_container';
import AbstractRendererOwl from 'web.AbstractRendererOwl';
import core from 'web.core';
-import field_registry from 'web.field_registry';
import KanbanColumnProgressBar from 'web.KanbanColumnProgressBar';
import { ComponentAdapter } from 'web.OwlCompatibility';
import QWeb from 'web.QWeb';
@@ -13,7 +13,6 @@ import utils from 'web.utils';
const { useState } = owl;
const _t = core._t;
-const KanbanActivity = field_registry.get('kanban_activity');
/**
* Owl Component Adapter for ActivityRecord which is KanbanRecord (Odoo Widget)
@@ -31,21 +30,6 @@ class ActivityRecordAdapter extends ComponentAdapter {
}
}
-/**
- * Owl Component Adapter for KanbanActivity.
- * TODO: Remove this adapter when KanbanActivity is a Component.
- */
-class ActivityCellAdapter extends ComponentAdapter {
- renderWidget() {
- this.widget._render();
- }
-
- updateWidget(nextProps) {
- const record = nextProps.widgetArgs[1];
- this.widget._reset(record);
- }
-}
-
/**
* Owl Component Adapter for KanbanColumnProgressBar (Odoo Widget)
* TODO: Remove this adapter when KanbanColumnProgressBar is a Component
@@ -94,7 +78,6 @@ class ActivityRenderer extends AbstractRendererOwl {
});
this.widgetComponents = {
ActivityRecord,
- KanbanActivity,
KanbanColumnProgressBar,
};
}
@@ -209,8 +192,8 @@ class ActivityRenderer extends AbstractRendererOwl {
}
ActivityRenderer.components = {
+ ActivityCellViewContainer,
ActivityRecordAdapter,
- ActivityCellAdapter,
KanbanColumnProgressBarAdapter,
};
ActivityRenderer.template = 'mail.ActivityRenderer';
diff --git a/addons/mail/static/src/models/activity.js b/addons/mail/static/src/models/activity.js
index 4b484c87c25..fc6fe52b9f7 100644
--- a/addons/mail/static/src/models/activity.js
+++ b/addons/mail/static/src/models/activity.js
@@ -179,7 +179,6 @@ registerModel({
/**
* @param {Object} param0
* @param {string} param0.feedback
- * @returns {Object}
*/
async markAsDoneAndScheduleNext({ feedback }) {
const thread = this.thread;
@@ -198,17 +197,18 @@ registerModel({
if (!action) {
return;
}
- this.env.services.action.doAction(
- action,
- {
- onClose: () => {
- if (!thread.exists()) {
- return;
- }
- thread.fetchData(['activities']);
+ await new Promise(resolve => {
+ this.env.services.action.doAction(
+ action,
+ {
+ onClose: resolve,
},
- },
- );
+ );
+ });
+ if (!thread.exists()) {
+ return;
+ }
+ thread.fetchData(['activities']);
},
},
fields: {
diff --git a/addons/mail/static/src/models/activity_cell_view.js b/addons/mail/static/src/models/activity_cell_view.js
new file mode 100644
index 00000000000..589ddfdd85a
--- /dev/null
+++ b/addons/mail/static/src/models/activity_cell_view.js
@@ -0,0 +1,53 @@
+/** @odoo-module **/
+
+import { registerModel } from '@mail/model/model_core';
+import { attr, many, one } from '@mail/model/model_field';
+import { clear } from '@mail/model/model_field_command';
+
+registerModel({
+ name: 'ActivityCellView',
+ recordMethods: {
+ onClick() {
+ this.update({ activityListPopoverView: this.activityListPopoverView ? clear() : {} });
+ },
+ },
+ fields: {
+ activityListPopoverView: one('PopoverView', {
+ inverse: 'activityCellViewOwnerAsActivityList',
+ }),
+ activityType: one('ActivityType', {
+ required: true,
+ }),
+ closestDeadline: attr({
+ required: true,
+ }),
+ closestDeadlineFormatted: attr({
+ compute() {
+ const date = moment(this.closestDeadline).toDate();
+ // To remove year only if current year
+ if (moment().year() === moment(date).year()) {
+ return date.toLocaleDateString(moment().locale(), {
+ day: 'numeric', month: 'short'
+ });
+ } else {
+ return moment(date).format('ll');
+ }
+ },
+ }),
+ contentRef: attr(),
+ filteredActivities: many('Activity', {
+ compute() {
+ return this.thread.activities.filter(activity => activity.type === this.activityType);
+ },
+ }),
+ id: attr({
+ identifying: true,
+ }),
+ reloadFunc: attr({
+ required: true,
+ }),
+ thread: one('Thread', {
+ required: true,
+ }),
+ },
+});
diff --git a/addons/mail/static/src/models/activity_list_view.js b/addons/mail/static/src/models/activity_list_view.js
index 34f30575724..4f000597acd 100644
--- a/addons/mail/static/src/models/activity_list_view.js
+++ b/addons/mail/static/src/models/activity_list_view.js
@@ -2,6 +2,7 @@
import { registerModel } from '@mail/model/model_core';
import { attr, many, one } from '@mail/model/model_field';
+import { clear } from '@mail/model/model_field_command';
import session from 'web.session';
@@ -29,13 +30,22 @@ registerModel({
},
recordMethods: {
onClickAddActivityButton() {
+ const reloadFunc = this.reloadFunc;
const thread = this.thread;
const webRecord = this.webRecord;
this.messaging.openActivityForm({
+ defaultActivityTypeId: this.popoverViewOwner.activityCellViewOwnerAsActivityList
+ ? this.popoverViewOwner.activityCellViewOwnerAsActivityList.activityType.id
+ : undefined,
thread,
}).then(() => {
thread.fetchData(['activities']);
- webRecord.model.load({ resId: thread.id });
+ if (reloadFunc) {
+ reloadFunc();
+ }
+ if (webRecord) {
+ webRecord.model.load({ resId: thread.id });
+ }
});
this.popoverViewOwner.delete();
},
@@ -43,6 +53,9 @@ registerModel({
fields: {
activities: many('Activity', {
compute() {
+ if (this.popoverViewOwner.activityCellViewOwnerAsActivityList) {
+ return this.popoverViewOwner.activityCellViewOwnerAsActivityList.filteredActivities;
+ }
return this.thread && this.thread.activities;
},
sort: [
@@ -70,9 +83,20 @@ registerModel({
identifying: true,
inverse: 'activityListView',
}),
+ reloadFunc: attr({
+ compute() {
+ return this.popoverViewOwner.activityCellViewOwnerAsActivityList ? this.popoverViewOwner.activityCellViewOwnerAsActivityList.reloadFunc : clear();
+ },
+ }),
thread: one('Thread', {
compute() {
- return this.popoverViewOwner.activityButtonViewOwnerAsActivityList.thread;
+ if (this.popoverViewOwner.activityButtonViewOwnerAsActivityList) {
+ return this.popoverViewOwner.activityButtonViewOwnerAsActivityList.thread;
+ }
+ if (this.popoverViewOwner.activityCellViewOwnerAsActivityList) {
+ return this.popoverViewOwner.activityCellViewOwnerAsActivityList.thread;
+ }
+ return clear();
},
required: true,
}),
@@ -81,9 +105,11 @@ registerModel({
}),
webRecord: attr({
compute() {
- return this.popoverViewOwner.activityButtonViewOwnerAsActivityList.webRecord;
+ if (this.popoverViewOwner.activityButtonViewOwnerAsActivityList) {
+ return this.popoverViewOwner.activityButtonViewOwnerAsActivityList.webRecord;
+ }
+ return clear();
},
- required: true,
}),
},
});
diff --git a/addons/mail/static/src/models/activity_list_view_item.js b/addons/mail/static/src/models/activity_list_view_item.js
index 9d3a5a8ffa8..e8995df1303 100644
--- a/addons/mail/static/src/models/activity_list_view_item.js
+++ b/addons/mail/static/src/models/activity_list_view_item.js
@@ -12,10 +12,16 @@ registerModel({
recordMethods: {
onClickEditActivityButton() {
const popoverViewOwner = this.activityListViewOwner.popoverViewOwner;
+ const reloadFunc = this.reloadFunc;
const webRecord = this.webRecord;
const thread = this.activity.thread;
this.activity.edit().then(() => {
- webRecord.model.load({ resId: thread.id });
+ if (reloadFunc) {
+ reloadFunc();
+ }
+ if (webRecord) {
+ webRecord.model.load({ resId: thread.id });
+ }
});
popoverViewOwner.delete();
},
@@ -117,11 +123,15 @@ registerModel({
markDoneView: one('ActivityMarkDonePopoverContentView', {
inverse: 'activityListViewItemOwner',
}),
+ reloadFunc: attr({
+ compute() {
+ return this.activityListViewOwner.reloadFunc ? this.activityListViewOwner.reloadFunc : clear();
+ },
+ }),
webRecord: attr({
compute() {
- return this.activityListViewOwner.webRecord;
+ return this.activityListViewOwner.webRecord ? this.activityListViewOwner.webRecord : clear();
},
- required: true,
}),
},
});
diff --git a/addons/mail/static/src/models/activity_mark_done_popover_content_view.js b/addons/mail/static/src/models/activity_mark_done_popover_content_view.js
index bf336944a48..daea5ac1bac 100644
--- a/addons/mail/static/src/models/activity_mark_done_popover_content_view.js
+++ b/addons/mail/static/src/models/activity_mark_done_popover_content_view.js
@@ -34,6 +34,7 @@ registerModel({
*/
async onClickDone() {
const chatter = this.activityViewOwner && this.activityViewOwner.activityBoxView.chatter;
+ const reloadFunc = this.reloadFunc;
const webRecord = this.webRecord;
const thread = this.activity.thread;
await this.activity.markAsDone({
@@ -42,6 +43,9 @@ registerModel({
if (chatter && chatter.exists() && chatter.component) {
chatter.reloadParentView();
}
+ if (reloadFunc) {
+ reloadFunc();
+ }
if (webRecord) {
webRecord.model.load({ resId: thread.id });
}
@@ -51,21 +55,25 @@ registerModel({
*/
async onClickDoneAndScheduleNext() {
const chatter = this.activityViewOwner && this.activityViewOwner.activityBoxView.chatter;
+ const reloadFunc = this.reloadFunc;
const webRecord = this.webRecord;
const thread = this.activity.thread;
const activityListViewOwner = this.activityListViewItemOwner && this.activityListViewItemOwner.activityListViewOwner;
- await this.activity.markAsDoneAndScheduleNext({
- feedback: this.feedbackTextareaRef.el.value,
- });
+ const activity = this.activity;
+ const feedback = this.feedbackTextareaRef.el.value;
+ if (activityListViewOwner && activityListViewOwner.exists()) {
+ activityListViewOwner.popoverViewOwner.delete();
+ }
+ await activity.markAsDoneAndScheduleNext({ feedback });
if (chatter && chatter.exists() && chatter.component) {
chatter.reloadParentView();
}
+ if (reloadFunc) {
+ reloadFunc();
+ }
if (webRecord) {
webRecord.model.load({ resId: thread.id });
}
- if (activityListViewOwner && activityListViewOwner.exists()) {
- activityListViewOwner.popoverViewOwner.delete();
- }
},
/**
* Handles keydown on this activity mark done.
@@ -141,6 +149,14 @@ registerModel({
identifying: true,
inverse: 'activityMarkDonePopoverContentView',
}),
+ reloadFunc: attr({
+ compute() {
+ if (this.activityListViewItemOwner) {
+ return this.activityListViewItemOwner.reloadFunc;
+ }
+ return clear();
+ },
+ }),
webRecord: attr({
compute() {
if (this.activityListViewItemOwner) {
diff --git a/addons/mail/static/src/models/file_uploader.js b/addons/mail/static/src/models/file_uploader.js
index e27655f25f5..41ee430fe13 100644
--- a/addons/mail/static/src/models/file_uploader.js
+++ b/addons/mail/static/src/models/file_uploader.js
@@ -94,6 +94,7 @@ registerModel({
* @returns {Promise}
*/
async _performUpload({ files }) {
+ const reloadFunc = this.activityListViewItemOwner && this.activityListViewItemOwner.reloadFunc;
const webRecord = this.activityListViewItemOwner && this.activityListViewItemOwner.webRecord;
const composer = this.composerView && this.composerView.composer; // save before async
const thread = this.thread; // save before async
@@ -149,15 +150,18 @@ registerModel({
}
}
}
+ if (activity && activity.exists()) {
+ await activity.markAsDone({ attachments });
+ }
+ if (reloadFunc) {
+ reloadFunc();
+ }
if (webRecord) {
webRecord.model.load({ resId: thread.id });
}
if (chatter && chatter.exists() && chatter.shouldReloadParentFromFileChanged) {
chatter.reloadParentView();
}
- if (activity && activity.exists()) {
- activity.markAsDone({ attachments });
- }
},
},
fields: {
diff --git a/addons/mail/static/src/models/popover_view.js b/addons/mail/static/src/models/popover_view.js
index 4afc474c418..043f0b014c5 100644
--- a/addons/mail/static/src/models/popover_view.js
+++ b/addons/mail/static/src/models/popover_view.js
@@ -50,9 +50,13 @@ registerModel({
identifying: true,
inverse: 'activityListPopoverView',
}),
+ activityCellViewOwnerAsActivityList: one('ActivityCellView', {
+ identifying: true,
+ inverse: 'activityListPopoverView',
+ }),
activityListView: one('ActivityListView', {
compute() {
- return this.activityButtonViewOwnerAsActivityList ? {} : clear();
+ return this.activityButtonViewOwnerAsActivityList || this.activityCellViewOwnerAsActivityList ? {} : clear();
},
inverse: 'popoverViewOwner',
}),
@@ -92,6 +96,9 @@ registerModel({
if (this.activityButtonViewOwnerAsActivityList) {
return this.activityButtonViewOwnerAsActivityList.buttonRef;
}
+ if (this.activityCellViewOwnerAsActivityList) {
+ return this.activityCellViewOwnerAsActivityList.contentRef;
+ }
if (this.messageActionViewOwnerAsReaction) {
return this.messageActionViewOwnerAsReaction.actionRef;
}
@@ -171,7 +178,7 @@ registerModel({
if (this.emojiPickerView) {
return this.emojiPickerView;
}
- if (this.activityButtonViewOwnerAsActivityList) {
+ if (this.activityButtonViewOwnerAsActivityList || this.activityCellViewOwnerAsActivityList) {
return this.activityListView;
}
if (this.messageNotificationPopoverContentView) {
@@ -217,7 +224,7 @@ registerModel({
if (this.emojiPickerView) {
return 'EmojiPickerView';
}
- if (this.activityButtonViewOwnerAsActivityList) {
+ if (this.activityButtonViewOwnerAsActivityList || this.activityCellViewOwnerAsActivityList) {
return 'ActivityListView';
}
if (this.messageNotificationPopoverContentView) {
@@ -296,6 +303,9 @@ registerModel({
if (this.activityButtonViewOwnerAsActivityList) {
return 'bottom-start';
}
+ if (this.activityCellViewOwnerAsActivityList) {
+ return 'bottom-start';
+ }
if (this.messageActionViewOwnerAsReaction) {
return 'top';
}
diff --git a/addons/mail/static/src/scss/activity_view.scss b/addons/mail/static/src/scss/activity_view.scss
index 329df6fcb4d..712c53fc440 100644
--- a/addons/mail/static/src/scss/activity_view.scss
+++ b/addons/mail/static/src/scss/activity_view.scss
@@ -4,11 +4,10 @@
thead > tr > th:first-of-type {
min-width: 300px;
}
- tbody > tr > td, tfoot > tr > td {
- cursor: pointer;
- }
}
.o_activity_summary_cell {
+ padding: 0; // to cancel unwanted padding of
coming from bootstrap
+
&.planned {
background-color: map-get($theme-colors, 'success');
}
@@ -18,19 +17,6 @@
&.today {
background-color: map-get($theme-colors, 'warning');
}
- .o_kanban_inline_block {
- min-height: 42px;
- }
- .dropdown-toggle {
- cursor: pointer;
- .o_closest_deadline {
- height: 42px;
- width: 100%;
- color: #FFF;
- text-align: center;
- line-height: 42px;
- }
- }
&.o_activity_empty_cell {
> i {
display: none;
@@ -44,19 +30,6 @@
}
}
}
- .o_activity_btn > .badge {
- @include o-position-absolute($bottom: 0, $right: 0);
-
- &.planned {
- @extend .text-success;
- }
- &.overdue {
- @extend .text-danger;
- }
- &.today {
- @extend .text-warning;
- }
- }
}
// it contains a kanban card representing the record
@@ -170,3 +143,7 @@
}
}
}
+
+.o_activity_view_table {
+ height: 1px; // this value is ignored on the table but it is necessary to ensure h-100 works on descendants to vertically center content inside cells
+}
diff --git a/addons/mail/static/src/xml/activity_view.xml b/addons/mail/static/src/xml/activity_view.xml
index f0deed6c449..94da654ab88 100644
--- a/addons/mail/static/src/xml/activity_view.xml
+++ b/addons/mail/static/src/xml/activity_view.xml
@@ -15,7 +15,7 @@
|