mirror of https://github.com/OCA/social.git
[MIG] mail_broker: Migration to 14.0
parent
294aa506d4
commit
ad8cbb3438
|
@ -5,7 +5,7 @@
|
|||
"name": "Mail Broker",
|
||||
"summary": """
|
||||
Set a broker""",
|
||||
"version": "13.0.1.0.0",
|
||||
"version": "14.0.1.0.0",
|
||||
"license": "AGPL-3",
|
||||
"author": "Creu Blanca,Odoo Community Association (OCA)",
|
||||
"website": "https://github.com/OCA/social",
|
||||
|
|
|
@ -17,6 +17,10 @@ class NewMailChatController(MailChatController):
|
|||
def _poll(self, dbname, channels, last, options):
|
||||
if request.session.uid:
|
||||
if request.env.user.has_group("mail_broker.broker_user"):
|
||||
for bot in request.env["mail.broker"].search([]):
|
||||
channels.append((request.db, "mail.broker", bot.id))
|
||||
return super()._poll(dbname, channels, last, options)
|
||||
channels = list(channels)
|
||||
for channel in request.env["mail.channel"].search(
|
||||
[("public", "=", "broker")]
|
||||
):
|
||||
channels.append((request.db, "mail.channel", channel.id))
|
||||
result = super()._poll(dbname, channels, last, options)
|
||||
return result
|
||||
|
|
|
@ -42,7 +42,7 @@ class MailBroker(models.Model):
|
|||
|
||||
def _get_channel_id(self, chat_token):
|
||||
return (
|
||||
self.env["mail.broker.channel"]
|
||||
self.env["mail.channel"]
|
||||
.search(
|
||||
[("token", "=", str(chat_token)), ("broker_id", "=", self.id)],
|
||||
limit=1,
|
||||
|
@ -94,7 +94,7 @@ class MailBroker(models.Model):
|
|||
"channel_name": "broker_%s" % record.id,
|
||||
"threads": [
|
||||
thread._get_thread_data()
|
||||
for thread in self.env["mail.broker.channel"].search(
|
||||
for thread in self.env["mail.channel"].search(
|
||||
[("show_on_app", "=", True), ("broker_id", "=", record.id)]
|
||||
)
|
||||
],
|
||||
|
@ -107,7 +107,7 @@ class MailBroker(models.Model):
|
|||
domain = [("broker_id", "=", self.id)]
|
||||
if name:
|
||||
domain += [("name", "ilike", "%" + name + "%")]
|
||||
return self.env["mail.broker.channel"].search(domain).read(["name"])
|
||||
return self.env["mail.channel"].search(domain).read(["name"])
|
||||
|
||||
def write(self, vals):
|
||||
res = super(MailBroker, self).write(vals)
|
||||
|
|
|
@ -7,39 +7,32 @@ from xmlrpc.client import DateTime
|
|||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class MailBrokerChannel(models.Model):
|
||||
_name = "mail.broker.channel"
|
||||
_description = "Mail Broker Channel"
|
||||
class MailChannel(models.Model):
|
||||
_inherit = "mail.channel"
|
||||
|
||||
name = fields.Char(required=True)
|
||||
active = fields.Boolean(default=True)
|
||||
token = fields.Char(required=True)
|
||||
broker_id = fields.Many2one("mail.broker", required=True)
|
||||
message_ids = fields.One2many(
|
||||
token = fields.Char()
|
||||
broker_id = fields.Many2one("mail.broker")
|
||||
broker_message_ids = fields.One2many(
|
||||
"mail.message.broker",
|
||||
inverse_name="channel_id",
|
||||
)
|
||||
mail_message_ids = fields.One2many(
|
||||
"mail.message",
|
||||
inverse_name="broker_channel_id",
|
||||
)
|
||||
last_message_date = fields.Datetime(
|
||||
compute="_compute_message_data",
|
||||
store=True,
|
||||
)
|
||||
unread = fields.Integer(
|
||||
public = fields.Selection(
|
||||
selection_add=[("broker", "Broker")], ondelete={"broker": "set default"}
|
||||
)
|
||||
channel_type = fields.Selection(
|
||||
selection_add=[("broker", "Broker")], ondelete={"broker": "set default"}
|
||||
)
|
||||
broker_unread = fields.Integer(
|
||||
compute="_compute_message_data",
|
||||
store=True,
|
||||
)
|
||||
broker_token = fields.Char(related="broker_id.token", store=True, required=False)
|
||||
show_on_app = fields.Boolean()
|
||||
partner_id = fields.Many2one("res.partner")
|
||||
message_main_attachment_id = fields.Many2one(
|
||||
string="Main Attachment",
|
||||
comodel_name="ir.attachment",
|
||||
index=True,
|
||||
copy=False,
|
||||
)
|
||||
broker_partner_id = fields.Many2one("res.partner")
|
||||
|
||||
def message_fetch(self, domain=False, limit=30):
|
||||
self.ensure_one()
|
||||
|
@ -52,9 +45,9 @@ class MailBrokerChannel(models.Model):
|
|||
)
|
||||
|
||||
@api.depends(
|
||||
"mail_message_ids",
|
||||
"mail_message_ids.date",
|
||||
"mail_message_ids.broker_unread",
|
||||
"message_ids",
|
||||
"message_ids.date",
|
||||
"message_ids.broker_unread",
|
||||
)
|
||||
def _compute_message_data(self):
|
||||
for r in self:
|
||||
|
@ -67,7 +60,7 @@ class MailBrokerChannel(models.Model):
|
|||
)
|
||||
.date
|
||||
)
|
||||
r.unread = self.env["mail.message"].search_count(
|
||||
r.broker_unread = self.env["mail.message"].search_count(
|
||||
[("broker_channel_id", "=", r.id), ("broker_unread", "=", True)]
|
||||
)
|
||||
|
||||
|
@ -78,12 +71,19 @@ class MailBrokerChannel(models.Model):
|
|||
"name": self.name,
|
||||
"last_message_date": self.last_message_date,
|
||||
"channel_type": "broker_thread",
|
||||
"unread": self.unread,
|
||||
"unread": self.broker_unread,
|
||||
"broker_id": self.broker_id.id,
|
||||
}
|
||||
|
||||
def _broker_message_post_vals(self, body, **kwargs):
|
||||
subtype_id = kwargs.get("subtype_id", False)
|
||||
def _broker_message_post_vals(
|
||||
self,
|
||||
body,
|
||||
subtype_id=False,
|
||||
author_id=False,
|
||||
date=False,
|
||||
message_id=False,
|
||||
**kwargs
|
||||
):
|
||||
if not subtype_id:
|
||||
subtype = kwargs.get("subtype") or "mt_note"
|
||||
if "." not in subtype:
|
||||
|
@ -91,21 +91,21 @@ class MailBrokerChannel(models.Model):
|
|||
subtype_id = self.env["ir.model.data"].xmlid_to_res_id(subtype)
|
||||
vals = {
|
||||
"channel_id": self.id,
|
||||
"channel_ids": [(4, self.id)],
|
||||
"body": body,
|
||||
"subtype_id": subtype_id,
|
||||
"model": self._name,
|
||||
"res_id": self.id,
|
||||
"broker_type": self.broker_id.broker_type,
|
||||
}
|
||||
if kwargs.get("author_id", False):
|
||||
vals["author_id"] = kwargs["author_id"]
|
||||
if "date" in kwargs:
|
||||
date = kwargs["date"]
|
||||
if author_id:
|
||||
vals["author_id"] = author_id
|
||||
if date:
|
||||
if isinstance(date, DateTime):
|
||||
date = datetime.strptime(str(date), "%Y%m%dT%H:%M:%S")
|
||||
vals["date"] = date
|
||||
if "message_id" in kwargs:
|
||||
vals["message_id"] = kwargs["message_id"]
|
||||
if message_id:
|
||||
vals["message_id"] = message_id
|
||||
vals["broker_unread"] = kwargs.get("broker_unread", False)
|
||||
vals["attachment_ids"] = []
|
||||
for attachment_id in kwargs.get("attachment_ids", []):
|
||||
|
@ -136,12 +136,40 @@ class MailBrokerChannel(models.Model):
|
|||
):
|
||||
return False
|
||||
vals = self._broker_message_post_vals(
|
||||
body, broker_unread=True, author_id=self.partner_id.id, **kwargs
|
||||
body, broker_unread=True, author_id=self.broker_partner_id.id, **kwargs
|
||||
)
|
||||
vals["state"] = "received"
|
||||
vals["broker_type"] = broker_type
|
||||
return self.env["mail.message.broker"].create(vals)
|
||||
|
||||
@api.returns("mail.message", lambda value: value.id)
|
||||
def message_post(self, *args, **kwargs):
|
||||
message = super().message_post(*args, **kwargs)
|
||||
if self.broker_id:
|
||||
self.env["mail.message.broker"].create(
|
||||
{
|
||||
"mail_message_id": message.id,
|
||||
"channel_id": self.id,
|
||||
}
|
||||
).send()
|
||||
return message
|
||||
|
||||
@api.model
|
||||
def channel_fetch_slot(self):
|
||||
result = super().channel_fetch_slot()
|
||||
broker_channels = self.env["mail.channel"].search([("public", "=", "broker")])
|
||||
result["channel_channel"] += broker_channels.channel_info()
|
||||
return result
|
||||
|
||||
def channel_info(self, *args, **kwargs):
|
||||
result = super().channel_info(*args, **kwargs)
|
||||
for channel, channel_info in zip(self, result):
|
||||
channel_info["broker_id"] = (
|
||||
channel.broker_id and channel.broker_id.id or False
|
||||
)
|
||||
channel_info["broker_unread_counter"] = channel.broker_unread
|
||||
return result
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
channels = super().create(vals_list)
|
||||
|
|
|
@ -9,7 +9,7 @@ class MailMessage(models.Model):
|
|||
_inherit = "mail.message"
|
||||
|
||||
broker_channel_id = fields.Many2one(
|
||||
"mail.broker.channel",
|
||||
"mail.channel",
|
||||
readonly=True,
|
||||
compute="_compute_broker_channel_id",
|
||||
store=True,
|
||||
|
@ -51,5 +51,7 @@ class MailMessage(models.Model):
|
|||
return result
|
||||
|
||||
def set_message_done(self):
|
||||
self.write({"broker_unread": False})
|
||||
# We need to set it as sudo in order to avoid collateral damages.
|
||||
# In fact, it is done with sudo on the original method
|
||||
self.sudo().filtered(lambda r: r.broker_unread).write({"broker_unread": False})
|
||||
return super().set_message_done()
|
||||
|
|
|
@ -25,9 +25,7 @@ class MailMessageBroker(models.Model):
|
|||
auto_join=True,
|
||||
)
|
||||
message_id = fields.Char(readonly=True)
|
||||
channel_id = fields.Many2one(
|
||||
"mail.broker.channel", required=True, ondelete="cascade"
|
||||
)
|
||||
channel_id = fields.Many2one("mail.channel", required=True, ondelete="cascade")
|
||||
state = fields.Selection(
|
||||
[
|
||||
("outgoing", "Outgoing"),
|
||||
|
@ -54,17 +52,10 @@ class MailMessageBroker(models.Model):
|
|||
if self.env.context.get("notify_broker", False):
|
||||
notifications = []
|
||||
for message in messages:
|
||||
notifications.append(
|
||||
[
|
||||
(
|
||||
self._cr.dbname,
|
||||
"mail.broker",
|
||||
message.channel_id.broker_id.id,
|
||||
),
|
||||
{"message": message.mail_message_id.message_format()[0]},
|
||||
]
|
||||
notifications += message.channel_id._channel_message_notifications(
|
||||
message.mail_message_id
|
||||
)
|
||||
self.env["bus.bus"].sendmany(notifications)
|
||||
self.env["bus.bus"].sudo().sendmany(notifications)
|
||||
return messages
|
||||
|
||||
def send(self, auto_commit=False, raise_exception=False, parse_mode="HTML"):
|
||||
|
|
|
@ -3,8 +3,5 @@ access_mail_message_broker_all,mail.message.broker.all,model_mail_message_broker
|
|||
access_mail_message_broker_portal,mail.message.broker.portal,model_mail_message_broker,base.group_portal,1,1,1,0
|
||||
access_mail_message_broker_user,mail.message.broker.user,model_mail_message_broker,base.group_user,1,1,1,0
|
||||
access_mail_message_broker_system,mail.message.broker.system,model_mail_message_broker,base.group_system,1,1,1,1
|
||||
access_mail_broker_channel_all,mail.telegram.chat.all,model_mail_broker_channel,,1,0,0,0
|
||||
access_mail_broker_channel_system,mail_broker_channel,model_mail_broker_channel,base.group_system,1,1,1,1
|
||||
access_mail_broker_all,mail.telegram.bot.all,model_mail_broker,,1,0,0,0
|
||||
access_mail_broker_channel_user,mail_broker_manager_bot,model_mail_broker_channel,mail_broker.broker_user,1,1,0,0
|
||||
access_mail_broker_system,mail_broker,model_mail_broker,base.group_system,1,1,1,1
|
||||
|
|
|
|
@ -11,4 +11,25 @@
|
|||
eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"
|
||||
/>
|
||||
</record>
|
||||
<record id="mail_channel_broker_rule" model="ir.rule">
|
||||
<field name="name">Mail.channel: access broker</field>
|
||||
<field name="model_id" ref="mail.model_mail_channel" />
|
||||
<field name="groups" eval="[(4, ref('mail_broker.broker_user'))]" />
|
||||
<field name="domain_force">[('public', '=', 'broker')]</field>
|
||||
<field name="perm_create" eval="False" />
|
||||
<field name="perm_unlink" eval="True" />
|
||||
</record>
|
||||
<record id="ir_rule_mail_channel_partner_group_user" model="ir.rule">
|
||||
<field
|
||||
name="name"
|
||||
>mail.channel.partner: write its own entries on broker channels</field>
|
||||
<field name="model_id" ref="mail.model_mail_channel_partner" />
|
||||
<field name="groups" eval="[(4, ref('mail_broker.broker_user'))]" />
|
||||
<field name="domain_force">[('channel_id.public', '=', 'broker')]</field>
|
||||
<field name="perm_read" eval="False" />
|
||||
<field name="perm_write" eval="True" />
|
||||
<field name="perm_create" eval="False" />
|
||||
<field name="perm_unlink" eval="True" />
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2018 ACSONE SA/NV
|
||||
# Copyright 2022 CreuBlanca
|
||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
|
||||
from odoo.addons.base_rest import restapi
|
||||
from odoo.addons.component.core import AbstractComponent
|
||||
|
@ -17,6 +17,12 @@ class BrokerMethodParams(restapi.RestMethodParam):
|
|||
def to_openapi_responses(self, service):
|
||||
return {"200": {"content": {}}}
|
||||
|
||||
def to_openapi_query_parameters(self, service, spec):
|
||||
return []
|
||||
|
||||
def to_json_schema(self, service, spec, direction):
|
||||
return {}
|
||||
|
||||
|
||||
class MailBrokerService(AbstractComponent):
|
||||
_inherit = "base.rest.service"
|
||||
|
@ -60,10 +66,10 @@ class MailBrokerService(AbstractComponent):
|
|||
def _get_channel(self, broker, token, update, force_create=False):
|
||||
chat_id = broker._get_channel_id(token)
|
||||
if chat_id:
|
||||
return self.env["mail.broker.channel"].browse(chat_id)
|
||||
return broker.env["mail.channel"].browse(chat_id)
|
||||
if not force_create and broker.has_new_channel_security:
|
||||
return False
|
||||
return self.env["mail.broker.channel"].create(
|
||||
return broker.env["mail.channel"].create(
|
||||
self._get_channel_vals(broker, token, update)
|
||||
)
|
||||
|
||||
|
@ -72,6 +78,8 @@ class MailBrokerService(AbstractComponent):
|
|||
"token": token,
|
||||
"broker_id": broker.id,
|
||||
"show_on_app": broker.show_on_app,
|
||||
"public": "broker",
|
||||
"channel_type": "broker",
|
||||
}
|
||||
|
||||
def _send(self, record, auto_commit=False, raise_exception=False, parse_mode=False):
|
||||
|
|
|
@ -1,429 +1,124 @@
|
|||
odoo.define("mail_broker.Broker", function (require) {
|
||||
odoo.define("mail_broker/static/src/broker.js", function (require) {
|
||||
"use strict";
|
||||
var BasicComposer = require("mail.composer.Basic");
|
||||
var ExtendedComposer = require("mail.composer.Extended");
|
||||
var core = require("web.core");
|
||||
var AbstractAction = require("web.AbstractAction");
|
||||
// Var ControlPanelMixin = require("web.ControlPanelMixin");
|
||||
var ThreadWidget = require("mail.widget.Thread");
|
||||
var dom = require("web.dom");
|
||||
const components = {
|
||||
Discuss: require("mail_broker/static/src/discuss.js"),
|
||||
};
|
||||
const AbstractAction = require("web.AbstractAction");
|
||||
const {action_registry} = require("web.core");
|
||||
|
||||
var QWeb = core.qweb;
|
||||
var _t = core._t;
|
||||
const {Component} = owl;
|
||||
|
||||
var Broker = AbstractAction.extend({
|
||||
contentTemplate: "mail_broker.broker",
|
||||
events: {
|
||||
"click .o_mail_channel_settings": "_onChannelSettingsClicked",
|
||||
"click .o_mail_discuss_item": "_onSelectBrokerChannel",
|
||||
"click .o_mail_sidebar_title .o_add": "_onSearchThread",
|
||||
"blur .o_mail_add_thread input": "_onSearchThreadBlur",
|
||||
},
|
||||
init: function (parent, action, options) {
|
||||
this._super.apply(this, arguments);
|
||||
template: "mail.widgets.Discuss",
|
||||
hasControlPanel: false,
|
||||
loadControlPanel: false,
|
||||
withSearchBar: false,
|
||||
searchMenuTypes: ["filter", "favorite"],
|
||||
/**
|
||||
* @override {web.AbstractAction}
|
||||
* @param {web.ActionManager} parent
|
||||
* @param {Object} action
|
||||
* @param {Object} [action.context]
|
||||
* @param {String} [action.context.active_id]
|
||||
* @param {Object} [action.params]
|
||||
* @param {String} [action.params.default_active_id]
|
||||
* @param {Object} [options={}]
|
||||
*/
|
||||
init(parent, action, options = {}) {
|
||||
this._super(...arguments);
|
||||
// Control panel attributes
|
||||
this.action = action;
|
||||
this.action_manager = parent;
|
||||
this.domain = [];
|
||||
this.options = options || {};
|
||||
this._threadsScrolltop = {};
|
||||
this._composerStates = {};
|
||||
this._defaultChatID =
|
||||
this.actionManager = parent;
|
||||
this.searchModelConfig.modelName = "mail.message";
|
||||
this.discuss = undefined;
|
||||
this.options = options;
|
||||
|
||||
this.component = undefined;
|
||||
|
||||
this._lastPushStateActiveThread = null;
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
async willStart() {
|
||||
await this._super(...arguments);
|
||||
this.env = Component.env;
|
||||
await this.env.messagingCreatedPromise;
|
||||
const initActiveId =
|
||||
this.options.active_id ||
|
||||
this.action.context.active_id ||
|
||||
this.action.params.default_active_id;
|
||||
this._selectedMessage = null;
|
||||
(this.action.context && this.action.context.active_id) ||
|
||||
(this.action.params && this.action.params.default_active_id) ||
|
||||
"mail.box_inbox";
|
||||
this.discuss = this.env.messaging.discuss;
|
||||
this.discuss.update({initActiveId});
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @override {web.AbstractAction}
|
||||
*/
|
||||
on_attach_callback: function () {
|
||||
if (this._thread) {
|
||||
this._threadWidget.scrollToPosition(
|
||||
this._threadsScrolltop[this._thread.getID()]
|
||||
);
|
||||
this._loadEnoughMessages();
|
||||
destroy() {
|
||||
if (this.component) {
|
||||
this.component.destroy();
|
||||
this.component = undefined;
|
||||
}
|
||||
this._super(...arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @override {web.AbstractAction}
|
||||
*/
|
||||
on_detach_callback: function () {
|
||||
if (this._thread) {
|
||||
this._threadsScrolltop[
|
||||
this._thread.getID()
|
||||
] = this._threadWidget.getScrolltop();
|
||||
}
|
||||
},
|
||||
start: function () {
|
||||
var self = this;
|
||||
|
||||
return this._super.apply(this, arguments).then(function () {
|
||||
return self._initRender();
|
||||
});
|
||||
/*
|
||||
Return this.alive($.when.apply($, defs))
|
||||
.then(function() {
|
||||
if (self._defaultChatID) {
|
||||
return self.alive(self._setThread(self._defaultChatID));
|
||||
}
|
||||
})
|
||||
|
||||
.then(function() {
|
||||
self._updateThreads();
|
||||
self._startListening();
|
||||
self._threadWidget.$el.on(
|
||||
"scroll",
|
||||
null,
|
||||
_.debounce(function() {
|
||||
var $noContent = self._threadWidget.$(".o_mail_no_content");
|
||||
if (
|
||||
self._threadWidget.getScrolltop() < 20 &&
|
||||
!self._thread.isAllHistoryLoaded() &&
|
||||
!$noContent.length
|
||||
) {
|
||||
self._loadMoreMessages();
|
||||
}
|
||||
if (self._threadWidget.isAtBottom()) {
|
||||
self._thread.markAsRead();
|
||||
}
|
||||
}, 100)
|
||||
);
|
||||
});
|
||||
*/
|
||||
},
|
||||
_initRender: function () {
|
||||
var self = this;
|
||||
this._basicComposer = new BasicComposer(this, {
|
||||
mentionPartnersRestricted: true,
|
||||
});
|
||||
this._extendedComposer = new ExtendedComposer(this, {
|
||||
mentionPartnersRestricted: true,
|
||||
});
|
||||
this._basicComposer
|
||||
.on("post_message", this, this._onPostMessage)
|
||||
.on("input_focused", this, this._onComposerFocused);
|
||||
this._extendedComposer
|
||||
.on("post_message", this, this._onPostMessage)
|
||||
.on("input_focused", this, this._onComposerFocused);
|
||||
this._renderButtons();
|
||||
|
||||
var defs = [];
|
||||
|
||||
defs.push(this._renderThread());
|
||||
defs.push(this._basicComposer.appendTo(this.$(".o_mail_discuss_content")));
|
||||
return Promise.all(defs)
|
||||
.then(function () {
|
||||
if (self._defaultChatID) {
|
||||
return self._setThread(self._defaultChatID);
|
||||
}
|
||||
})
|
||||
|
||||
.then(function () {
|
||||
self._updateThreads();
|
||||
self._startListening();
|
||||
self._threadWidget.$el.on(
|
||||
"scroll",
|
||||
null,
|
||||
_.debounce(function () {
|
||||
var $noContent = self._threadWidget.$(".o_mail_no_content");
|
||||
if (
|
||||
self._threadWidget.getScrolltop() < 20 &&
|
||||
!self._thread.isAllHistoryLoaded() &&
|
||||
!$noContent.length
|
||||
) {
|
||||
self._loadMoreMessages();
|
||||
}
|
||||
if (self._threadWidget.isAtBottom()) {
|
||||
self._thread.markAsRead();
|
||||
}
|
||||
}, 100)
|
||||
);
|
||||
});
|
||||
},
|
||||
_startListening: function () {
|
||||
this.call("mail_service", "getMailBus").on(
|
||||
"new_message",
|
||||
this,
|
||||
this._onNewMessage
|
||||
);
|
||||
},
|
||||
_setThread: function (threadID) {
|
||||
this._storeThreadState();
|
||||
var thread = this.call("mail_service", "getThread", threadID);
|
||||
if (!thread) {
|
||||
on_attach_callback() {
|
||||
this._super(...arguments);
|
||||
if (this.component) {
|
||||
// Prevent twice call to on_attach_callback (FIXME)
|
||||
return;
|
||||
}
|
||||
this._thread = thread;
|
||||
|
||||
var self = this;
|
||||
this.messagesSeparatorPosition = undefined;
|
||||
return this._fetchAndRenderThread().then(function () {
|
||||
self._thread.markAsRead();
|
||||
// Restore scroll position and composer of the new
|
||||
// current thread
|
||||
self._restoreThreadState();
|
||||
|
||||
// Update control panel before focusing the composer, otherwise
|
||||
// focus is on the searchview
|
||||
self.set("title", self._thread.getTitle());
|
||||
|
||||
self.action_manager.do_push_state({
|
||||
action: self.action.id,
|
||||
active_id: self._thread.getID(),
|
||||
});
|
||||
});
|
||||
},
|
||||
_storeThreadState: function () {
|
||||
if (this._thread) {
|
||||
this._threadsScrolltop[
|
||||
this._thread.getID()
|
||||
] = this._threadWidget.getScrolltop();
|
||||
}
|
||||
},
|
||||
_loadEnoughMessages: function () {
|
||||
var $el = this._threadWidget.el;
|
||||
var loadMoreMessages =
|
||||
$el.clientHeight &&
|
||||
$el.clientHeight === $el.scrollHeight &&
|
||||
!this._thread.isAllHistoryLoaded();
|
||||
if (loadMoreMessages) {
|
||||
return this._loadMoreMessages().then(
|
||||
this._loadEnoughMessages.bind(this)
|
||||
);
|
||||
}
|
||||
},
|
||||
_getThreadRenderingOptions: function () {
|
||||
if (_.isUndefined(this.messagesSeparatorPosition)) {
|
||||
if (this._unreadCounter) {
|
||||
var messageID = this._thread.getLastSeenMessageID();
|
||||
this.messagesSeparatorPosition = messageID || "top";
|
||||
} else {
|
||||
// No unread message -> don't display separator
|
||||
this.messagesSeparatorPosition = false;
|
||||
}
|
||||
}
|
||||
return {
|
||||
displayLoadMore: !this._thread.isAllHistoryLoaded(),
|
||||
squashCloseMessages: true,
|
||||
messagesSeparatorPosition: this.messagesSeparatorPosition,
|
||||
displayEmailIcons: false,
|
||||
displayReplyIcons: false,
|
||||
displayBottomThreadFreeSpace: true,
|
||||
displayModerationCommands: false,
|
||||
displayMarkAsRead: false,
|
||||
displayDocumentLinks: false,
|
||||
displayStars: false,
|
||||
};
|
||||
},
|
||||
_fetchAndRenderThread: function () {
|
||||
var self = this;
|
||||
return this._thread.fetchMessages().then(function () {
|
||||
self._threadWidget.render(
|
||||
self._thread,
|
||||
self._getThreadRenderingOptions()
|
||||
);
|
||||
return self._loadEnoughMessages();
|
||||
});
|
||||
},
|
||||
_renderButtons: function () {
|
||||
// This is a hook just in case some buttons are required
|
||||
},
|
||||
_renderThread: function () {
|
||||
this._threadWidget = new ThreadWidget(this, {
|
||||
areMessageAttachmentsDeletable: false,
|
||||
loadMoreOnScroll: true,
|
||||
});
|
||||
this._threadWidget.on("load_more_messages", this, this._loadMoreMessages);
|
||||
return this._threadWidget.appendTo(this.$(".o_mail_discuss_content"));
|
||||
},
|
||||
_renderSidebar: function (options) {
|
||||
var $sidebar = $(
|
||||
QWeb.render("mail_broker.broker.Sidebar", {
|
||||
activeThreadID: this._thread ? this._thread.getID() : undefined,
|
||||
bots: options.bots,
|
||||
})
|
||||
);
|
||||
return $sidebar;
|
||||
},
|
||||
_restoreThreadState: function () {
|
||||
var $newMessagesSeparator = this.$(".o_thread_new_messages_separator");
|
||||
if ($newMessagesSeparator.length) {
|
||||
this._threadWidget.$el.scrollTo($newMessagesSeparator);
|
||||
} else {
|
||||
var newThreadScrolltop = this._threadsScrolltop[this._thread.getID()];
|
||||
this._threadWidget.scrollToPosition(newThreadScrolltop);
|
||||
}
|
||||
},
|
||||
_updateThreads: function () {
|
||||
var bots = this.call("mail_service", "getBrokerBots");
|
||||
var $sidebar = this._renderSidebar({
|
||||
bots: bots,
|
||||
});
|
||||
this.$(".o_mail_discuss_sidebar").html($sidebar.contents());
|
||||
var self = this;
|
||||
_.each(bots, function (bot, broker_id) {
|
||||
var $input = self.$(
|
||||
".o_mail_add_thread[data-bot=" + broker_id + "] input"
|
||||
);
|
||||
self._prepareAddThreadInput($input, broker_id, bot);
|
||||
});
|
||||
},
|
||||
_prepareAddThreadInput: function ($input, broker_id) {
|
||||
var self = this;
|
||||
$input.autocomplete({
|
||||
source: function (request, response) {
|
||||
self._lastSearchVal = _.escape(request.term);
|
||||
self._searchChannel(broker_id, self._lastSearchVal).then(function (
|
||||
result
|
||||
) {
|
||||
response(result);
|
||||
});
|
||||
},
|
||||
select: function (ev, ui) {
|
||||
self._setThread("broker_thread_" + ui.item.id);
|
||||
self._updateThreads();
|
||||
},
|
||||
focus: function (ev) {
|
||||
ev.preventDefault();
|
||||
},
|
||||
html: true,
|
||||
});
|
||||
},
|
||||
_loadMoreMessages: function () {
|
||||
var self = this;
|
||||
var oldestMessageID = this.$(".o_thread_message").first().data("messageId");
|
||||
var oldestMessageSelector =
|
||||
'.o_thread_message[data-message-id="' + oldestMessageID + '"]';
|
||||
var offset = -dom.getPosition(document.querySelector(oldestMessageSelector))
|
||||
.top;
|
||||
return this._thread.fetchMessages({loadMore: true}).then(function () {
|
||||
if (self.messagesSeparatorPosition === "top") {
|
||||
// Reset value to re-compute separator position
|
||||
self.messagesSeparatorPosition = undefined;
|
||||
}
|
||||
self._threadWidget.render(
|
||||
self._thread,
|
||||
self._getThreadRenderingOptions()
|
||||
);
|
||||
offset += dom.getPosition(document.querySelector(oldestMessageSelector))
|
||||
.top;
|
||||
self._threadWidget.scrollToPosition(offset);
|
||||
});
|
||||
},
|
||||
_onSearchThread: function (ev) {
|
||||
ev.preventDefault();
|
||||
var bot = $(ev.target).data("bot");
|
||||
this.$(".o_mail_add_thread[data-bot=" + bot + "]")
|
||||
.show()
|
||||
.find("input")
|
||||
.focus();
|
||||
},
|
||||
_onSearchThreadBlur: function () {
|
||||
this.$(".o_mail_add_thread").hide();
|
||||
},
|
||||
_onChannelSettingsClicked: function (ev) {
|
||||
ev.preventDefault();
|
||||
const DiscussComponent = components.Discuss;
|
||||
this.component = new DiscussComponent();
|
||||
this._pushStateActionManagerEventListener = (ev) => {
|
||||
ev.stopPropagation();
|
||||
var threadID = $(ev.target).data("thread-id");
|
||||
var thread = this.call("mail_service", "getThread", threadID);
|
||||
this.do_action({
|
||||
type: "ir.actions.act_window",
|
||||
res_model: "mail.broker.channel",
|
||||
res_id: thread.resId,
|
||||
name: _t("Configure chat"),
|
||||
views: [[false, "form"]],
|
||||
target: "new",
|
||||
});
|
||||
},
|
||||
_onNewMessage: function (message) {
|
||||
var thread_id = "broker_thread_" + message.broker_channel_id;
|
||||
if (this._thread && thread_id === this._thread.getID()) {
|
||||
this._thread.markAsRead();
|
||||
var shouldScroll = this._threadWidget.isAtBottom();
|
||||
var self = this;
|
||||
this._fetchAndRenderThread().then(function () {
|
||||
if (shouldScroll) {
|
||||
self._threadWidget.scrollToMessage({
|
||||
msgID: message.getID(),
|
||||
});
|
||||
if (this._lastPushStateActiveThread === this.discuss.thread) {
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
// Re-render sidebar to indicate that there is a new message in
|
||||
// The corresponding threads
|
||||
this._updateThreads();
|
||||
// Dump scroll position of threads in which the new message arrived
|
||||
this._threadsScrolltop = _.omit(
|
||||
this._threadsScrolltop,
|
||||
message.getThreadIDs()
|
||||
);
|
||||
},
|
||||
_searchChannel: function (broker_id, searchVal) {
|
||||
return this._rpc({
|
||||
model: "mail.broker",
|
||||
method: "channel_search",
|
||||
args: [[parseInt(broker_id, 10)], searchVal],
|
||||
}).then(function (result) {
|
||||
var values = [];
|
||||
_.each(result, function (channel) {
|
||||
var escapedName = _.escape(channel.name);
|
||||
values.push(
|
||||
_.extend(channel, {
|
||||
value: escapedName,
|
||||
label: escapedName,
|
||||
})
|
||||
);
|
||||
});
|
||||
return values;
|
||||
});
|
||||
},
|
||||
_onComposerFocused: function () {
|
||||
// Hook
|
||||
},
|
||||
_onSelectBrokerChannel: function (ev) {
|
||||
ev.preventDefault();
|
||||
var threadID = $(ev.currentTarget).data("thread-id");
|
||||
this._setThread(threadID);
|
||||
this._updateThreads();
|
||||
},
|
||||
_onPostMessage: function (messageData) {
|
||||
var self = this;
|
||||
var options = {};
|
||||
if (this._selectedMessage) {
|
||||
messageData.subtype = this._selectedMessage.isNote()
|
||||
? "mail.mt_note"
|
||||
: "mail.mt_comment";
|
||||
messageData.subtype_id = false;
|
||||
messageData.broker_type = "comment";
|
||||
this._pushStateActionManager();
|
||||
this._lastPushStateActiveThread = this.discuss.thread;
|
||||
};
|
||||
|
||||
options.documentID = this._selectedMessage.getDocumentID();
|
||||
options.documentModel = this._selectedMessage.getDocumentModel();
|
||||
}
|
||||
this._thread
|
||||
.postMessage(messageData, options)
|
||||
.then(function () {
|
||||
if (self._selectedMessage) {
|
||||
self._renderSnackbar(
|
||||
"mail.discuss.MessageSentSnackbar",
|
||||
{
|
||||
documentName: self._selectedMessage.getDocumentName(),
|
||||
},
|
||||
5000
|
||||
this.el.addEventListener(
|
||||
"o-push-state-action-manager",
|
||||
this._pushStateActionManagerEventListener
|
||||
);
|
||||
self._unselectMessage();
|
||||
} else {
|
||||
self._threadWidget.scrollToBottom();
|
||||
return this.component.mount(this.el);
|
||||
},
|
||||
/**
|
||||
* @override {web.AbstractAction}
|
||||
*/
|
||||
on_detach_callback() {
|
||||
this._super(...arguments);
|
||||
if (this.component) {
|
||||
this.component.destroy();
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
// TODO: Display notifications
|
||||
this.component = undefined;
|
||||
this.el.removeEventListener(
|
||||
"o-push-state-action-manager",
|
||||
this._pushStateActionManagerEventListener
|
||||
);
|
||||
this._lastPushStateActiveThread = null;
|
||||
},
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Private
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_pushStateActionManager() {
|
||||
this.actionManager.do_push_state({
|
||||
action: this.action.id,
|
||||
active_id: this.discuss.activeId,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
core.action_registry.add("mail.broker", Broker);
|
||||
action_registry.add("mail.broker", Broker);
|
||||
|
||||
return Broker;
|
||||
});
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
odoo.define("mail_broker/static/src/js/broker_model.js", function (require) {
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
registerNewModel,
|
||||
registerInstancePatchModel,
|
||||
registerFieldPatchModel,
|
||||
registerClassPatchModel,
|
||||
} = require("mail/static/src/model/model_core.js");
|
||||
const {attr, many2one} = require("mail/static/src/model/model_field.js");
|
||||
|
||||
function factoryBroker(dependencies) {
|
||||
class Broker extends dependencies["mail.model"] {}
|
||||
Broker.modelName = "mail.broker";
|
||||
Broker.fields = {
|
||||
id: attr(),
|
||||
name: attr(),
|
||||
};
|
||||
|
||||
return Broker;
|
||||
}
|
||||
registerNewModel("mail.broker", factoryBroker);
|
||||
registerInstancePatchModel(
|
||||
"mail.messaging_initializer",
|
||||
"mail_broker/static/src/js/broker_model.js",
|
||||
{
|
||||
async _init({broker_slots}) {
|
||||
_.each(broker_slots, (broker_slot) =>
|
||||
this.env.models["mail.broker"].insert(
|
||||
Object.assign({model: "mail.broker"}, broker_slot)
|
||||
)
|
||||
);
|
||||
return this._super(...arguments);
|
||||
},
|
||||
}
|
||||
);
|
||||
registerInstancePatchModel(
|
||||
"mail.discuss",
|
||||
"mail_broker/static/src/js/broker_model.js",
|
||||
{
|
||||
async openBrokerChannel(thread) {
|
||||
this.update({
|
||||
brokerChannel: [["link", thread]],
|
||||
});
|
||||
this.focus();
|
||||
this.env.bus.trigger("do-action", {
|
||||
action: "mail_broker.mail_broker_action_window",
|
||||
options: {
|
||||
active_id: this.threadToActiveId(this),
|
||||
clear_breadcrumbs: false,
|
||||
on_reverse_breadcrumb: () => this.close(),
|
||||
},
|
||||
});
|
||||
},
|
||||
}
|
||||
);
|
||||
registerClassPatchModel(
|
||||
"mail.thread",
|
||||
"mail_broker/static/src/js/broker_model.js",
|
||||
{
|
||||
convertData(data) {
|
||||
const data2 = this._super(data);
|
||||
data2.broker_id = data.broker_id;
|
||||
data2.broker_unread_counter = data.broker_unread_counter;
|
||||
return data2;
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
registerFieldPatchModel(
|
||||
"mail.discuss",
|
||||
"mail_broker/static/src/js/broker_model.js",
|
||||
{
|
||||
brokerChannel: many2one("mail.thread"),
|
||||
}
|
||||
);
|
||||
registerFieldPatchModel(
|
||||
"mail.thread",
|
||||
"mail_broker/static/src/js/broker_model.js",
|
||||
{
|
||||
broker_id: attr(),
|
||||
broker_unread_counter: attr(),
|
||||
}
|
||||
);
|
||||
});
|
|
@ -0,0 +1,69 @@
|
|||
odoo.define("mail_broker/static/src/discuss.js", function (require) {
|
||||
"use strict";
|
||||
|
||||
const Discuss = require("mail/static/src/components/discuss/discuss.js");
|
||||
const DiscussSidebar = require("mail/static/src/components/discuss_sidebar/discuss_sidebar.js");
|
||||
const DiscussSidebarItem = require("mail/static/src/components/discuss_sidebar_item/discuss_sidebar_item.js");
|
||||
|
||||
const {Component} = owl;
|
||||
|
||||
class BrokerDiscussSidebarItem extends DiscussSidebarItem {
|
||||
get counter() {
|
||||
if (this.thread.channel_type === "broker") {
|
||||
return this.thread.broker_unread_counter;
|
||||
}
|
||||
return super.counter;
|
||||
}
|
||||
}
|
||||
|
||||
class DiscussSidebarBroker extends Component {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
this.mailBroker = this.env.models["mail.broker"].get(this.props.brokerId);
|
||||
}
|
||||
get quickSearchOrderedAndPinnedBrokerChannels() {
|
||||
return this.env.models["mail.thread"]
|
||||
.all((channel) => channel.broker_id === this.mailBroker.id)
|
||||
.sort((c1, c2) => {
|
||||
if (!c1.lastMessage && !c2.lastMessage) {
|
||||
return c1.id < c2.id;
|
||||
} else if (!c2.lastMessage) {
|
||||
return -1;
|
||||
} else if (!c1.lastMessage) {
|
||||
return 1;
|
||||
}
|
||||
return c1.lastMessage.id < c2.lastMessage.id ? -1 : 1;
|
||||
});
|
||||
}
|
||||
}
|
||||
Object.assign(DiscussSidebarBroker, {
|
||||
components: Object.assign(DiscussSidebar.components, {
|
||||
DiscussSidebarItem: BrokerDiscussSidebarItem,
|
||||
}),
|
||||
props: {
|
||||
brokerId: String,
|
||||
},
|
||||
template: "mail_broker.DiscussSidebarBroker",
|
||||
});
|
||||
|
||||
class BrokerDiscussSidebar extends DiscussSidebar {
|
||||
get mailBrokers() {
|
||||
return this.env.models["mail.broker"].all();
|
||||
}
|
||||
}
|
||||
Object.assign(BrokerDiscussSidebar, {
|
||||
components: Object.assign(DiscussSidebar.components, {DiscussSidebarBroker}),
|
||||
props: DiscussSidebar.props,
|
||||
template: "mail_broker.DiscussSidebar",
|
||||
});
|
||||
|
||||
class NewDiscuss extends Discuss {}
|
||||
Object.assign(NewDiscuss, {
|
||||
components: Object.assign({}, Discuss.components, {
|
||||
DiscussSidebar: BrokerDiscussSidebar,
|
||||
}),
|
||||
props: Discuss.props,
|
||||
template: Discuss.template,
|
||||
});
|
||||
return NewDiscuss;
|
||||
});
|
|
@ -1,18 +1,23 @@
|
|||
odoo.define("mail_broker.model.Message", function (require) {
|
||||
odoo.define("mail_broker/static/src/js/message.js", function (require) {
|
||||
"use strict";
|
||||
|
||||
var Message = require("mail.model.Message");
|
||||
const {registerClassPatchModel} = require("mail/static/src/model/model_core.js");
|
||||
|
||||
Message.include({
|
||||
init: function (parent, data) {
|
||||
this._super.apply(this, arguments);
|
||||
this.broker_channel_id = data.broker_channel_id || false;
|
||||
this.broker_unread = data.broker_unread || false;
|
||||
this.broker_type = data.broker_type || false;
|
||||
this.customer_status = data.customer_status || false;
|
||||
registerClassPatchModel(
|
||||
"mail.message",
|
||||
"mail/static/src/models/message/message.js",
|
||||
{
|
||||
convertData(data) {
|
||||
const data2 = this._super(data);
|
||||
if ("broker_channel_id" in data) {
|
||||
data2.broker_channel_id = data.broker_channel_id || false;
|
||||
data2.broker_unread = data.broker_unread || false;
|
||||
data2.broker_type = data.broker_type || false;
|
||||
data2.customer_status = data.customer_status || false;
|
||||
data2.isNeedaction = data2.isNeedaction || data.broker_unread;
|
||||
}
|
||||
return data2;
|
||||
},
|
||||
isNeedaction: function () {
|
||||
return this._super.apply(this, arguments) || this.broker_unread;
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
@ -65,7 +65,7 @@ odoo.define("mail_broker.BrokerThread", function (require) {
|
|||
domain = [["id", "<", minMessageID]].concat(domain);
|
||||
}
|
||||
return this._rpc({
|
||||
model: "mail.broker.channel",
|
||||
model: "mail.channel",
|
||||
method: "message_fetch",
|
||||
args: [[this.resId], domain],
|
||||
kwargs: this._getFetchMessagesKwargs(options),
|
||||
|
|
|
@ -1,5 +1,63 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates xml:space="preserve">
|
||||
<t t-name="mail_broker.broker">
|
||||
<div class="o_widget_Discuss" />
|
||||
</t>
|
||||
<t t-name="mail_broker.DiscussSidebarBroker" owl="1">
|
||||
<div>
|
||||
<div class="o_DiscussSidebar_groupHeader">
|
||||
<div
|
||||
class="o_DiscussSidebar_groupHeaderItem o_DiscussSidebar_groupTitle o-clickable"
|
||||
t-esc="mailBroker.name"
|
||||
/>
|
||||
<div class="o-autogrow" />
|
||||
<div
|
||||
class="o_DiscussSidebar_groupHeaderItem o_DiscussSidebar_groupHeaderItemAdd fa fa-plus"
|
||||
t-on-click="_onClickChannelAdd"
|
||||
title="Add or join a channel"
|
||||
/>
|
||||
</div>
|
||||
<div class="o_DiscussSidebar_list">
|
||||
<div class="o_DiscussSidebar_item o_DiscussSidebar_itemNew">
|
||||
<AutocompleteInput
|
||||
class="o_DiscussSidebar_itemNewInput"
|
||||
customClass="'o_DiscussSidebar_newChannelAutocompleteSuggestions'"
|
||||
isFocusOnMount="true"
|
||||
isHtml="true"
|
||||
placeholder="FIND_OR_CREATE_CHANNEL"
|
||||
select="_onAddChannelAutocompleteSelect"
|
||||
source="_onAddChannelAutocompleteSource"
|
||||
/>
|
||||
</div>
|
||||
<t
|
||||
t-foreach="quickSearchOrderedAndPinnedBrokerChannels"
|
||||
t-as="brokerChannel"
|
||||
t-key="brokerChannel.localId"
|
||||
>
|
||||
<DiscussSidebarItem
|
||||
class="o_DiscussSidebar_item"
|
||||
threadLocalId="brokerChannel.localId"
|
||||
/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="mail_broker.DiscussSidebar" owl="1">
|
||||
<div name="root" class="o_DiscussSidebar">
|
||||
<div class="o_DiscussSidebar_group o_DiscussSidebar_groupChannel">
|
||||
<div class="o_DiscussSidebar_list">
|
||||
<t
|
||||
t-foreach="mailBrokers"
|
||||
t-as="mailBroker"
|
||||
t-key="mailBroker.localId"
|
||||
>
|
||||
<DiscussSidebarBroker brokerId="mailBroker.localId" />
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<!--
|
||||
<t t-extend="mail.widget.Thread.Message">
|
||||
<t t-jquery=".o_mail_info" t-operation="append">
|
||||
<span
|
||||
|
@ -44,5 +102,5 @@
|
|||
<t t-jquery=".o_input" t-operation="attributes">
|
||||
<attribute name="t-attf-data-bot">#{bot_key}</attribute>
|
||||
</t>
|
||||
</t>
|
||||
</t>-->
|
||||
</templates>
|
||||
|
|
|
@ -8,9 +8,16 @@
|
|||
/>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="/mail_broker/static/src/js/manager.js"
|
||||
src="/mail_broker/static/src/js/discuss.js"
|
||||
/><!--
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="/mail_broker/static/src/js/messaging_initializer.js"
|
||||
/>-->
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="/mail_broker/static/src/js/broker_model.js"
|
||||
/>
|
||||
<script type="text/javascript" src="/mail_broker/static/src/js/thread.js" />
|
||||
<script type="text/javascript" src="/mail_broker/static/src/js/broker.js" />
|
||||
<link rel="stylesheet" href="/mail_broker/static/src/scss/broker.scss" />
|
||||
</xpath>
|
||||
|
|
|
@ -2,72 +2,10 @@
|
|||
<!-- Copyright 2020 Creu Blanca
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
|
||||
<odoo>
|
||||
<record model="ir.ui.view" id="mail_broker_channel_form_view">
|
||||
<field name="name">mail.broker.channel.form</field>
|
||||
<field name="model">mail.broker.channel</field>
|
||||
<field name="priority">10</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<header />
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box" />
|
||||
<group>
|
||||
<field name="name" />
|
||||
<field name="partner_id" />
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="mail_broker_channel_form_root_view">
|
||||
<field name="name">mail.broker.channel.form</field>
|
||||
<field name="model">mail.broker.channel</field>
|
||||
<field name="inherit_id" ref="mail_broker.mail_broker_channel_form_view" />
|
||||
<field name="groups_id" eval="[(6, 0, [ref('base.group_system')])]" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="name" position="after">
|
||||
<field name="token" />
|
||||
<field name="broker_id" />
|
||||
<field name="show_on_app" />
|
||||
<field name="token" />
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="mail_broker_channel_search_view">
|
||||
<field name="name">mail.broker.channel.search (in mail_broker)</field>
|
||||
<field name="model">mail.broker.channel</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field name="name" />
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="mail_broker_channel_tree_view">
|
||||
<field name="name">mail.broker.channel.tree (in mail_broker)</field>
|
||||
<field name="model">mail.broker.channel</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="name" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.actions.act_window" id="mail_broker_channel_act_window">
|
||||
<field name="name">Mail Broker Channel</field>
|
||||
<field name="res_model">mail.broker.channel</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="domain">[]</field>
|
||||
<field name="context">{}</field>
|
||||
</record>
|
||||
<record model="ir.ui.menu" id="mail_broker_channel_menu">
|
||||
<field name="name">Mail Broker Channel</field>
|
||||
<field name="parent_id" ref="base.menu_email" />
|
||||
<field name="action" ref="mail_broker_channel_act_window" />
|
||||
<field name="sequence" eval="16" />
|
||||
</record>
|
||||
<record id="mail_broker_action_window" model="ir.actions.client">
|
||||
<field name="name">Broker</field>
|
||||
<field name="tag">mail.broker</field>
|
||||
<field name="res_model">mail.broker.channel</field>
|
||||
<field name="res_model">mail.channel</field>
|
||||
<field name="params" eval="{}" />
|
||||
</record>
|
||||
<menuitem
|
||||
|
|
Loading…
Reference in New Issue