mirror of https://github.com/OCA/social.git
commit
164298a511
|
@ -134,6 +134,8 @@ class IrMailServer(models.Model):
|
|||
smtp_user=None,
|
||||
smtp_password=None,
|
||||
smtp_encryption=None,
|
||||
smtp_ssl_certificate=None,
|
||||
smtp_ssl_private_key=None,
|
||||
smtp_debug=False,
|
||||
smtp_session=None,
|
||||
):
|
||||
|
@ -149,6 +151,8 @@ class IrMailServer(models.Model):
|
|||
smtp_user=smtp_user,
|
||||
smtp_password=smtp_password,
|
||||
smtp_encryption=smtp_encryption,
|
||||
smtp_ssl_certificate=smtp_ssl_certificate,
|
||||
smtp_ssl_private_key=smtp_ssl_private_key,
|
||||
smtp_debug=smtp_debug,
|
||||
smtp_session=smtp_session,
|
||||
)
|
||||
|
|
|
@ -99,46 +99,35 @@ class MailThread(models.AbstractModel):
|
|||
res = super()._fields_view_get(
|
||||
view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu
|
||||
)
|
||||
if view_type not in {"search", "form"}:
|
||||
if view_type != "search":
|
||||
return res
|
||||
doc = etree.XML(res["arch"])
|
||||
if view_type == "search":
|
||||
# Modify view to add new filter element
|
||||
nodes = doc.xpath("//search")
|
||||
if nodes:
|
||||
# Create filter element
|
||||
new_filter = etree.Element(
|
||||
"filter",
|
||||
{
|
||||
"string": _("Failed sent messages"),
|
||||
"name": "failed_message_ids",
|
||||
"domain": str(
|
||||
# Modify view to add new filter element
|
||||
nodes = doc.xpath("//search")
|
||||
if nodes:
|
||||
# Create filter element
|
||||
new_filter = etree.Element(
|
||||
"filter",
|
||||
{
|
||||
"string": _("Failed sent messages"),
|
||||
"name": "failed_message_ids",
|
||||
"domain": str(
|
||||
[
|
||||
[
|
||||
[
|
||||
"failed_message_ids.mail_tracking_ids.state",
|
||||
"in",
|
||||
list(self.env["mail.message"].get_failed_states()),
|
||||
],
|
||||
[
|
||||
"failed_message_ids.mail_tracking_needs_action",
|
||||
"=",
|
||||
True,
|
||||
],
|
||||
]
|
||||
),
|
||||
},
|
||||
)
|
||||
nodes[0].append(etree.Element("separator"))
|
||||
nodes[0].append(new_filter)
|
||||
elif view_type == "form":
|
||||
# Modify view to add new field element
|
||||
nodes = doc.xpath("//field[@name='message_ids' and @widget='mail_thread']")
|
||||
if nodes:
|
||||
# Create field
|
||||
field_failed_messages = etree.Element(
|
||||
"field",
|
||||
{"name": "failed_message_ids", "widget": "mail_failed_message"},
|
||||
)
|
||||
nodes[0].addprevious(field_failed_messages)
|
||||
"failed_message_ids.mail_tracking_ids.state",
|
||||
"in",
|
||||
list(self.env["mail.message"].get_failed_states()),
|
||||
],
|
||||
[
|
||||
"failed_message_ids.mail_tracking_needs_action",
|
||||
"=",
|
||||
True,
|
||||
],
|
||||
]
|
||||
),
|
||||
},
|
||||
)
|
||||
nodes[0].append(etree.Element("separator"))
|
||||
nodes[0].append(new_filter)
|
||||
res["arch"] = etree.tostring(doc, encoding="unicode")
|
||||
return res
|
||||
|
|
|
@ -1 +1,4 @@
|
|||
* Add pivot for tracking events and mail trackings
|
||||
* Integrate with the core `mail.notification` model. A soft way would be to write a
|
||||
notification event along with the mail.tracking.event ones. Another way could be
|
||||
to merge both models and build the module features on top of it. This might imply
|
||||
a refactor though.
|
||||
|
|
|
@ -7,7 +7,7 @@ import {attr} from "@mail/model/model_field";
|
|||
|
||||
registerInstancePatchModel(
|
||||
"mail.chatter",
|
||||
"mail/static/src/models/chatter/chatter.js",
|
||||
"mail/static/src/models/chatter/chatter.esm.js",
|
||||
{
|
||||
async refresh() {
|
||||
this._super(...arguments);
|
||||
|
@ -24,8 +24,12 @@ registerInstancePatchModel(
|
|||
},
|
||||
}
|
||||
);
|
||||
registerFieldPatchModel("mail.chatter", "mail/static/src/models/chatter/chatter.js", {
|
||||
isMessageFailedBoxVisible: attr({
|
||||
default: true,
|
||||
}),
|
||||
});
|
||||
registerFieldPatchModel(
|
||||
"mail.chatter",
|
||||
"mail/static/src/models/chatter/chatter.esm.js",
|
||||
{
|
||||
isMessageFailedBoxVisible: attr({
|
||||
default: true,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
|
|
@ -1,411 +0,0 @@
|
|||
/* Copyright 2019 Alexandre Díaz
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). */
|
||||
odoo.define("mail_tracking.FailedMessageDiscuss", function (require) {
|
||||
"use strict";
|
||||
|
||||
// To be considered:
|
||||
// - One message can be displayed in many threads
|
||||
// - A thread can be a mailbox, channel, ...
|
||||
// - A mailbox is a type of thread that is displayed on top of
|
||||
// the discuss menu, has a counter, etc...
|
||||
|
||||
var MailManagerNotif = require("mail.Manager.Notification");
|
||||
var AbstractMessage = require("mail.model.AbstractMessage");
|
||||
var Message = require("mail.model.Message");
|
||||
var Discuss = require("mail.Discuss");
|
||||
var MailManager = require("mail.Manager");
|
||||
var Mailbox = require("mail.model.Mailbox");
|
||||
var Dialog = require("web.Dialog");
|
||||
var core = require("web.core");
|
||||
|
||||
var QWeb = core.qweb;
|
||||
var _t = core._t;
|
||||
|
||||
AbstractMessage.include({
|
||||
/**
|
||||
* Abstract declaration to know if a message is included in the
|
||||
* failed mailbox. By default it should be false.
|
||||
*
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
isFailed: function () {
|
||||
return false;
|
||||
},
|
||||
});
|
||||
|
||||
Message.include({
|
||||
/**
|
||||
* Overrides to store information from server
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
init: function (parent, data) {
|
||||
this._isFailedMessage = data.is_failed_message;
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* Implementation to know if a message is included in the
|
||||
* failed mailbox.
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
isFailed: function () {
|
||||
return _.contains(this._threadIDs, "mailbox_failed");
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds/Removes message to/from failed mailbox
|
||||
*
|
||||
* @param {Boolean} failed
|
||||
*/
|
||||
setFailed: function (failed) {
|
||||
if (failed) {
|
||||
this._addThread("mailbox_failed");
|
||||
} else {
|
||||
this.removeThread("mailbox_failed");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Include the message in the 'failed' mailbox if needed
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
_processMailboxes: function () {
|
||||
this.setFailed(this._isFailedMessage);
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
|
||||
MailManagerNotif.include({
|
||||
/**
|
||||
* Overrides to handle changes in the 'mail_tracking_needs_action' flag
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
_handlePartnerNotification: function (data) {
|
||||
if (data.type === "toggle_tracking_status") {
|
||||
this._handleChangeTrackingNeedsActionNotification(data);
|
||||
} else {
|
||||
// Workaround to avoid call '_handlePartnerChannelNotification'
|
||||
// because this is related with the failed mailbox, not a
|
||||
// channel.
|
||||
this._super.apply(this, arguments);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This method updates messages in the failed mailbox when the flag
|
||||
* 'mail_tracking_needs_action' was changed to False. This can
|
||||
* remove/add the message from/to failed mailbox and update mailbox
|
||||
* counter.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} data
|
||||
*/
|
||||
_handleChangeTrackingNeedsActionNotification: function (data) {
|
||||
var self = this;
|
||||
var failed = this.getMailbox("failed");
|
||||
_.each(data.message_ids, function (messageID) {
|
||||
var message = _.find(self._messages, function (msg) {
|
||||
return msg.getID() === messageID;
|
||||
});
|
||||
if (message) {
|
||||
message.setFailed(data.needs_actions);
|
||||
if (message.isFailed() === false) {
|
||||
self._removeMessageFromThread("mailbox_failed", message);
|
||||
} else {
|
||||
self._addMessageToThreads(message, []);
|
||||
var channelFailed = self.getMailbox("failed");
|
||||
channelFailed.invalidateCaches();
|
||||
}
|
||||
self._mailBus.trigger("update_message", message, data.type);
|
||||
}
|
||||
});
|
||||
|
||||
if (data.needs_actions) {
|
||||
// Increase failed counter if message is marked as failed
|
||||
failed.incrementMailboxCounter(data.message_ids.length);
|
||||
} else {
|
||||
// Decrease failed counter if message is removed from failed
|
||||
failed.decrementMailboxCounter(data.message_ids.length);
|
||||
}
|
||||
|
||||
// Trigger event to refresh threads
|
||||
this._mailBus.trigger("update_failed", failed.getMailboxCounter());
|
||||
},
|
||||
});
|
||||
|
||||
Discuss.include({
|
||||
events: _.extend({}, Discuss.prototype.events, {
|
||||
"click .o_failed_message_retry": "_onRetryFailedMessage",
|
||||
"click .o_failed_message_reviewed": "_onMarkFailedMessageReviewed",
|
||||
}),
|
||||
|
||||
/**
|
||||
* Paramaters used to render 'failed' mailbox entry in Discuss
|
||||
*
|
||||
* @private
|
||||
* @returns {Object}
|
||||
*/
|
||||
_sidebarQWebParams: function () {
|
||||
var failed = this.call("mail_service", "getMailbox", "failed");
|
||||
return {
|
||||
activeThreadID: this._thread ? this._thread.getID() : undefined,
|
||||
failedCounter: failed.getMailboxCounter(),
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Render 'failed' mailbox menu entry in Discuss
|
||||
* - Initial render
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
_renderSidebar: function () {
|
||||
var $sidebar = this._super.apply(this, arguments);
|
||||
// Because Odoo implementation isn't designed to be inherited
|
||||
// properly, we inject 'failed' button using jQuery.
|
||||
var $failed_item = $(
|
||||
QWeb.render("mail_tracking.SidebarFailed", this._sidebarQWebParams())
|
||||
);
|
||||
$failed_item.insertAfter(
|
||||
$sidebar.find(".o_mail_discuss_title_main").filter(":last")
|
||||
);
|
||||
return $sidebar;
|
||||
},
|
||||
|
||||
/**
|
||||
* Render 'failed' mailbox menu entry in Discuss
|
||||
* - Update status render (not called if the mailbox is empty)
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
_renderSidebarMailboxes: function () {
|
||||
this._super.apply(this, arguments);
|
||||
this.$(".o_mail_discuss_sidebar_mailboxes").append(
|
||||
QWeb.render("mail_tracking.SidebarFailed", this._sidebarQWebParams())
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Overrides to listen click on 'Set all as reviewed' button
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
_renderButtons: function () {
|
||||
this._super.apply(this, arguments);
|
||||
this.$btn_set_all_reviewed = this.$buttons.find(
|
||||
".o_mail_discuss_button_set_all_reviewed"
|
||||
);
|
||||
this.$btn_set_all_reviewed.on(
|
||||
"click",
|
||||
$.proxy(this, "_onSetAllAsReviewedClicked")
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Show or hide 'set all as reviewed' button in discuss mailbox
|
||||
*
|
||||
* This means in which thread the button should be displayed.
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
_updateControlPanelButtons: function (thread) {
|
||||
this.$btn_set_all_reviewed
|
||||
.toggleClass("d-none", thread.getID() !== "mailbox_failed")
|
||||
.toggleClass("d-md-inline-block", thread.getID() === "mailbox_failed");
|
||||
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* Overrides to update 'set all as reviewed' button.
|
||||
*
|
||||
* Disabled button if doesn't have more failed messages
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
_updateButtonStatus: function (disabled, type) {
|
||||
if (this._thread.getID() === "mailbox_failed") {
|
||||
this.$btn_set_all_reviewed.toggleClass("disabled", disabled);
|
||||
// Display Rainbowman when all failed messages are reviewed
|
||||
// through 'TOGGLE TRACKING STATUS' or marking last failed
|
||||
// message as reviewed
|
||||
if (disabled && type === "toggle_tracking_status") {
|
||||
this.trigger_up("show_effect", {
|
||||
message: _t("Congratulations, your failed mailbox is empty"),
|
||||
type: "rainbow_man",
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Overrides to update messages in 'failed' mailbox thread
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
_onMessageUpdated: function (message, type) {
|
||||
var self = this;
|
||||
var currentThreadID = this._thread.getID();
|
||||
if (currentThreadID === "mailbox_failed" && !message.isFailed()) {
|
||||
this._thread.fetchMessages(this.domain).then(function () {
|
||||
var options = self._getThreadRenderingOptions();
|
||||
self._threadWidget
|
||||
.removeMessageAndRender(message.getID(), self._thread, options)
|
||||
.then(function () {
|
||||
self._updateButtonStatus(!self._thread.hasMessages(), type);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// Workaround to avoid calling '_fetchAndRenderThread' and
|
||||
// refetching thread messages because these messages are
|
||||
// actually fetched above.
|
||||
this._super.apply(this, arguments);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide reply feature in the 'failed' mailbox, where it has no sense.
|
||||
* Show instead 'Retry' and 'Set as reviewed' buttons.
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
_getThreadRenderingOptions: function () {
|
||||
var values = this._super.apply(this, arguments);
|
||||
if (this._thread.getID() === "mailbox_failed") {
|
||||
values.displayEmailIcons = true;
|
||||
values.displayReplyIcons = false;
|
||||
values.displayRetryButton = true;
|
||||
values.displayReviewedButton = true;
|
||||
}
|
||||
return values;
|
||||
},
|
||||
|
||||
/**
|
||||
* Listen also to the event that refreshes thread messages
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
_startListening: function () {
|
||||
this._super.apply(this, arguments);
|
||||
this.call("mail_service", "getMailBus").on(
|
||||
"update_failed",
|
||||
this,
|
||||
this._throttledUpdateThreads
|
||||
);
|
||||
},
|
||||
|
||||
// Handlers
|
||||
/**
|
||||
* Open the resend mail.resend.message wizard
|
||||
*
|
||||
* @private
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onRetryFailedMessage: function (event) {
|
||||
event.preventDefault();
|
||||
var messageID = $(event.currentTarget).data("message-id");
|
||||
this.do_action("mail.mail_resend_message_action", {
|
||||
additional_context: {
|
||||
mail_message_to_resend: messageID,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle 'mail_tracking_needs_action' flag
|
||||
*
|
||||
* @private
|
||||
* @param {Event} event
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_onMarkFailedMessageReviewed: function (event) {
|
||||
event.preventDefault();
|
||||
var messageID = $(event.currentTarget).data("message-id");
|
||||
return this._rpc({
|
||||
model: "mail.message",
|
||||
method: "set_need_action_done",
|
||||
args: [[messageID]],
|
||||
context: this.getSession().user_context,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Inheritable method that call thread implementation
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onSetAllAsReviewedClicked: function () {
|
||||
var self = this;
|
||||
var failed = this.call("mail_service", "getMailbox", "failed");
|
||||
var failed_counter = failed.getMailboxCounter();
|
||||
if (failed_counter > 0) {
|
||||
var promptText = _.str.sprintf(
|
||||
_t(
|
||||
"Do you really want to mark as reviewed all the" +
|
||||
" failed messages (%d)?"
|
||||
),
|
||||
failed_counter
|
||||
);
|
||||
Dialog.confirm(this, promptText, {
|
||||
confirm_callback: function () {
|
||||
self._thread.setAllMessagesAsReviewed();
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
MailManager.include({
|
||||
/**
|
||||
* Add the 'failed' mailbox
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
_updateMailboxesFromServer: function (data) {
|
||||
this._super.apply(this, arguments);
|
||||
this._addMailbox({
|
||||
id: "failed",
|
||||
name: _t("Failed"),
|
||||
mailboxCounter: data.failed_counter || 0,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Mailbox.include({
|
||||
/**
|
||||
* Overrides to add domain for 'failed' mailbox thread
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
_getThreadDomain: function () {
|
||||
if (this._id === "mailbox_failed") {
|
||||
return [["is_failed_message", "=", true]];
|
||||
}
|
||||
// Workaround to avoid throw 'Missing domain' exception. Call _super
|
||||
// without a valid (hard-coded) thread id causes that exeception.
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets all messages from the mailbox as reviewed.
|
||||
*
|
||||
* At the moment, this method makes only sense for 'Failed'.
|
||||
*
|
||||
* @returns {$.Promise} resolved when all messages have been marked as
|
||||
* reviewed on the server
|
||||
*/
|
||||
setAllMessagesAsReviewed: function () {
|
||||
if (this._id === "mailbox_failed" && this.getMailboxCounter() > 0) {
|
||||
return this._rpc({
|
||||
model: "mail.message",
|
||||
method: "set_all_as_reviewed",
|
||||
});
|
||||
}
|
||||
return $.when();
|
||||
},
|
||||
});
|
||||
});
|
|
@ -40,6 +40,13 @@ export class MessageFailedBox extends Component {
|
|||
this.chatter.thread.refreshMessagefailed();
|
||||
this.chatter.thread.refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Chatter}
|
||||
*/
|
||||
get chatter() {
|
||||
return this.messaging.models["mail.chatter"].get(this.props.chatterLocalId);
|
||||
}
|
||||
}
|
||||
|
||||
Object.assign(MessageFailedBox, {
|
||||
|
|
|
@ -8,7 +8,7 @@ import {one2many} from "@mail/model/model_field";
|
|||
|
||||
registerInstancePatchModel(
|
||||
"mail.thread",
|
||||
"mail_tracking/static/src/js/failed_message/thread.js",
|
||||
"mail_tracking/static/src/js/failed_message/thread.esm.js",
|
||||
{
|
||||
async refreshMessagefailed() {
|
||||
var id = this.__values.id;
|
||||
|
@ -49,7 +49,7 @@ registerInstancePatchModel(
|
|||
|
||||
registerFieldPatchModel(
|
||||
"mail.thread",
|
||||
"mail_tracking/static/src/js/failed_message/thread.js",
|
||||
"mail_tracking/static/src/js/failed_message/thread.esm.js",
|
||||
{
|
||||
messagefailed: one2many("mail.message.failed", {
|
||||
inverse: "thread",
|
||||
|
|
|
@ -9,7 +9,7 @@ import {attr} from "@mail/model/model_field";
|
|||
|
||||
registerClassPatchModel(
|
||||
"mail.message",
|
||||
"mail_tracking/static/src/js/mail_tracking.js",
|
||||
"mail_tracking/static/src/js/mail_tracking.esm.js",
|
||||
{
|
||||
convertData(data) {
|
||||
const data2 = this._super(data);
|
||||
|
@ -23,7 +23,7 @@ registerClassPatchModel(
|
|||
|
||||
registerFieldPatchModel(
|
||||
"mail.message",
|
||||
"mail_tracking/static/src/js/mail_tracking.js",
|
||||
"mail_tracking/static/src/js/mail_tracking.esm.js",
|
||||
{
|
||||
partner_trackings: attr(),
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ registerFieldPatchModel(
|
|||
|
||||
registerInstancePatchModel(
|
||||
"mail.model",
|
||||
"mail_tracking/static/src/js/mail_tracking.js",
|
||||
"mail_tracking/static/src/js/mail_tracking.esm.js",
|
||||
{
|
||||
hasPartnerTrackings() {
|
||||
return _.some(this.__values.partner_trackings);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import {Message} from "@mail/components/message/message";
|
||||
import {patch} from "web.utils";
|
||||
|
||||
patch(Message.prototype, "mail_tracking/static/src/js/message.js", {
|
||||
patch(Message.prototype, "mail_tracking/static/src/js/message.esm.js", {
|
||||
constructor() {
|
||||
this._super(...arguments);
|
||||
},
|
||||
|
|
|
@ -43,11 +43,11 @@
|
|||
<t t-if="messagefailed.author">
|
||||
<img
|
||||
class="o_Activity_userAvatar"
|
||||
t-attf-src="/web/image/res.users/{{ messagefailed.author_id }}/image_128"
|
||||
t-attf-src="/web/image/res.partner/{{ messagefailed.author_id }}/avatar_128"
|
||||
t-att-alt="messagefailed.author"
|
||||
/>
|
||||
</t>
|
||||
<div class="o_Activity_iconContainer bg-danger-full">
|
||||
<div class="o_Activity_iconContainer bg-danger">
|
||||
<i class="o_Activity_icon fa fa-exclamation" />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -116,7 +116,7 @@
|
|||
expr="//div[hasclass('o_Chatter_scrollPanel')]/t[@t-if='chatter.isAttachmentBoxVisible']"
|
||||
position="before"
|
||||
>
|
||||
<t t-if="chatter.thread">
|
||||
<t>
|
||||
<MessageFailedBox
|
||||
class="o_Chatter_activityBox"
|
||||
chatterLocalId="chatter.localId"
|
||||
|
|
|
@ -172,7 +172,7 @@
|
|||
<record id="action_view_mail_tracking_email" model="ir.actions.act_window">
|
||||
<field name="name">MailTracking emails</field>
|
||||
<field name="res_model">mail.tracking.email</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_mode">tree,form,pivot</field>
|
||||
<field name="search_view_id" ref="view_mail_tracking_email_search" />
|
||||
</record>
|
||||
|
||||
|
|
|
@ -195,7 +195,7 @@
|
|||
<record id="action_view_mail_tracking_event" model="ir.actions.act_window">
|
||||
<field name="name">MailTracking events</field>
|
||||
<field name="res_model">mail.tracking.event</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_mode">tree,form,pivot</field>
|
||||
<field name="search_view_id" ref="view_mail_tracking_event_search" />
|
||||
</record>
|
||||
|
||||
|
|
Loading…
Reference in New Issue