Browse Source

[13.0][MIG] bi_view_editor

myc-14.0-py3o
Andrea 4 years ago
parent
commit
fd47f75e72
  1. 2
      bi_view_editor/__init__.py
  2. 5
      bi_view_editor/__manifest__.py
  3. 48
      bi_view_editor/hooks.py
  4. 0
      bi_view_editor/i18n/nl.po
  5. 28
      bi_view_editor/models/bve_view.py
  6. 41
      bi_view_editor/models/bve_view_line.py
  7. 24
      bi_view_editor/models/ir_model.py
  8. 1
      bi_view_editor/models/models.py
  9. 7
      bi_view_editor/readme/USAGE.rst
  10. 5
      bi_view_editor/static/src/css/bve.css
  11. 44
      bi_view_editor/static/src/js/bi_view_editor.FieldList.js
  12. 4
      bi_view_editor/static/src/js/bi_view_editor.ModelList.js
  13. 12
      bi_view_editor/static/src/js/bi_view_editor.js
  14. 20
      bi_view_editor/static/src/xml/bi_view_editor.xml
  15. 33
      bi_view_editor/tests/test_bi_view.py
  16. 18
      bi_view_editor/views/bve_view.xml

2
bi_view_editor/__init__.py

@ -2,4 +2,4 @@
from . import models
from . import wizard
from .hooks import post_load, uninstall_hook
from .hooks import uninstall_hook

5
bi_view_editor/__manifest__.py

@ -9,9 +9,9 @@
"license": "AGPL-3",
"website": "https://github.com/OCA/reporting-engine",
"category": "Reporting",
"version": "12.0.1.0.0",
"version": "13.0.1.0.0",
"development_status": "Beta",
"depends": ["web",],
"depends": ["web"],
"data": [
"security/ir.model.access.csv",
"security/rules.xml",
@ -19,7 +19,6 @@
"views/bve_view.xml",
],
"qweb": ["static/src/xml/bi_view_editor.xml"],
"post_load": "post_load",
"uninstall_hook": "uninstall_hook",
"installable": True,
}

48
bi_view_editor/hooks.py

@ -1,54 +1,6 @@
# Copyright 2015-2019 Onestein (<https://www.onestein.eu>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
import logging
from odoo import SUPERUSER_ID, api, modules
from odoo.tools import existing_tables, topological_sort
_logger = logging.getLogger(__name__)
def _bi_view(_name):
return _name.startswith("x_bve.")
def post_load():
def check_tables_exist(self, cr):
"""
Verify that all tables are present and try to initialize
those that are missing.
"""
# This monkey patch is meant to avoid that the _logger writes
# warning and error messages, while running an update all,
# in case the model is a bi-view-generated model.
env = api.Environment(cr, SUPERUSER_ID, {})
table2model = {
model._table: name
for name, model in env.items()
if not model._abstract and not _bi_view(name) # here is the patch
}
missing_tables = set(table2model).difference(existing_tables(cr, table2model))
if missing_tables:
missing = {table2model[table] for table in missing_tables}
_logger.warning("Models have no table: %s.", ", ".join(missing))
# recreate missing tables following model dependencies
deps = {name: model._depends for name, model in env.items()}
for name in topological_sort(deps):
if name in missing:
_logger.info("Recreate table of model %s.", name)
env[name].init()
# check again, and log errors if tables are still missing
missing_tables = set(table2model).difference(
existing_tables(cr, table2model)
)
for table in missing_tables:
_logger.error("Model %s has no table.", table2model[table])
modules.registry.Registry.check_tables_exist = check_tables_exist
def uninstall_hook(cr, registry):
# delete dirty data that could cause problems

0
bi_view_editor/i18n/nl.po

28
bi_view_editor/models/bve_view.py

@ -60,7 +60,7 @@ class BveView(models.Model):
line_ids = self._sync_lines_and_data(bve_view.data)
bve_view.write({"line_ids": line_ids})
name = fields.Char(required=True, copy=False)
name = fields.Char(required=True, copy=False, default="")
model_name = fields.Char(compute="_compute_model_name", store=True)
note = fields.Text(string="Notes")
state = fields.Selection(
@ -100,7 +100,7 @@ class BveView(models.Model):
)
query = fields.Text(compute="_compute_sql_query")
over_condition = fields.Text(
states={"draft": [("readonly", False),],},
states={"draft": [("readonly", False)]},
readonly=True,
help="Condition to be inserted in the OVER part "
"of the ID's row_number function.\n"
@ -169,7 +169,7 @@ class BveView(models.Model):
try:
png_base64_image = base64.b64encode(graph.create_png())
bve_view.er_diagram_image = png_base64_image
except:
except Exception:
bve_view.er_diagram_image = False
def _create_view_arch(self):
@ -191,7 +191,7 @@ class BveView(models.Model):
return '<field name="{}" {} />'.format(line.name, res)
bve_field_lines = self.field_ids.filtered(lambda l: l.in_list)
return list(map(_get_field_attrs, bve_field_lines))
return list(map(_get_field_attrs, bve_field_lines.sorted("sequence")))
def _create_bve_view(self):
self.ensure_one()
@ -236,7 +236,7 @@ class BveView(models.Model):
"model": self.model_name,
"priority": 16,
"arch": """<?xml version="1.0"?>
<search string="Search BI View">
<search>
{}
</search>
""".format(
@ -254,7 +254,7 @@ class BveView(models.Model):
"model": self.model_name,
"priority": 16,
"arch": """<?xml version="1.0"?>
<tree string="List Analysis" create="false">
<tree create="false">
{}
</tree>
""".format(
@ -272,7 +272,6 @@ class BveView(models.Model):
"name": self.name,
"res_model": self.model_name,
"type": "ir.actions.act_window",
"view_type": "form",
"view_mode": "tree,graph,pivot",
"view_id": tree_view.id,
"context": "{'service_name': '%s'}" % self.name,
@ -475,7 +474,7 @@ class BveView(models.Model):
self.env["ir.model.access"]
.sudo()
.search(
[("model_id", "=", line_model.id), ("perm_read", "=", True),]
[("model_id", "=", line_model.id), ("perm_read", "=", True)]
)
)
group_list = ""
@ -495,20 +494,18 @@ class BveView(models.Model):
if not self.line_ids:
raise ValidationError(_("No data to process."))
if any(not line.model_id for line in self.line_ids):
invalid_lines = self.line_ids.filtered(lambda l: not l.model_id)
missing_models = set(invalid_lines.mapped("model_name"))
missing_models = ", ".join(missing_models)
if invalid_lines:
missing_models = ", ".join(set(invalid_lines.mapped("model_name")))
raise ValidationError(
_(
"Following models are missing: %s.\n"
"Probably some modules were uninstalled." % (missing_models,)
)
)
if any(not line.field_id for line in self.line_ids):
invalid_lines = self.line_ids.filtered(lambda l: not l.field_id)
missing_fields = set(invalid_lines.mapped("field_name"))
missing_fields = ", ".join(missing_fields)
if invalid_lines:
missing_fields = ", ".join(set(invalid_lines.mapped("field_name")))
raise ValidationError(
_("Following fields are missing: {}.".format(missing_fields))
)
@ -520,7 +517,6 @@ class BveView(models.Model):
action["display_name"] = _("BI View")
return action
@api.multi
def copy(self, default=None):
self.ensure_one()
default = dict(default or {}, name=_("%s (copy)") % self.name)
@ -623,6 +619,8 @@ class BveView(models.Model):
@api.model
def get_clean_list(self, data_dict):
serialized_data = data_dict
if type(data_dict) == str:
serialized_data = json.loads(data_dict)
table_alias_list = set()
for item in serialized_data:

41
bi_view_editor/models/bve_view_line.py

@ -1,4 +1,4 @@
# Copyright 2015-2019 Onestein (<https://www.onestein.eu>)
# Copyright 2015-2020 Onestein (<https://www.onestein.eu>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import _, api, fields, models
@ -12,11 +12,11 @@ class BveViewLine(models.Model):
name = fields.Char(compute="_compute_name")
sequence = fields.Integer(default=1)
bve_view_id = fields.Many2one("bve.view", ondelete="cascade")
model_id = fields.Many2one("ir.model", string="Model")
model_name = fields.Char(compute="_compute_model_name", store=True)
table_alias = fields.Char()
join_model_id = fields.Many2one("ir.model", string="Join Model")
field_id = fields.Many2one("ir.model.fields", string="Field")
model_id = fields.Many2one("ir.model")
model_name = fields.Char(related="model_id.model", store=True, string="Model Name")
table_alias = fields.Char(required=True)
join_model_id = fields.Many2one("ir.model")
field_id = fields.Many2one("ir.model.fields")
field_name = fields.Char(compute="_compute_model_field_name", store=True)
ttype = fields.Char(string="Type")
description = fields.Char(translate=True)
@ -29,7 +29,7 @@ class BveViewLine(models.Model):
measure = fields.Boolean()
in_list = fields.Boolean()
list_attr = fields.Selection(
[("sum", "Sum"), ("avg", "Average"),], string="List Attribute", default="sum"
[("sum", "Sum"), ("avg", "Average")], string="List Attribute", default="sum"
)
view_field_type = fields.Char(compute="_compute_view_field_type")
@ -44,12 +44,11 @@ class BveViewLine(models.Model):
@api.constrains("row", "column", "measure")
def _constrains_options_check(self):
measure_types = ["float", "integer", "monetary"]
for line in self.filtered(lambda l: l.row or l.column):
if line.join_model_id or line.ttype in measure_types:
lines = self.filtered(lambda l: l.join_model_id or l.ttype in measure_types)
if lines.filtered(lambda l: l.row or l.column):
err_msg = _("This field cannot be a row or a column.")
raise ValidationError(err_msg)
for line in self.filtered(lambda l: l.measure):
if line.join_model_id or line.ttype not in measure_types:
if lines.filtered(lambda l: l.measure):
err_msg = _("This field cannot be a measure.")
raise ValidationError(err_msg)
@ -67,21 +66,17 @@ class BveViewLine(models.Model):
@api.depends("field_id", "sequence")
def _compute_name(self):
for line in self.filtered(lambda l: l.field_id):
field_name = line.field_id.name
line.name = "x_bve_{}_{}".format(line.table_alias, field_name)
@api.depends("model_id")
def _compute_model_name(self):
for line in self.filtered(lambda l: l.model_id):
line.model_name = line.model_id.model
for line in self:
line.name = False
if line.field_id:
line.name = "x_bve_{}_{}".format(line.table_alias, line.field_id.name)
@api.depends("field_id")
def _compute_model_field_name(self):
for line in self.filtered(lambda l: l.field_id):
field_name = line.description
model_name = line.model_name
line.field_name = "{} ({})".format(field_name, model_name)
for line in self:
line.field_name = False
if line.field_id:
line.field_name = "{} ({})".format(line.description, line.model_name)
def _prepare_field_vals(self):
vals_list = []

24
bi_view_editor/models/ir_model.py

@ -3,7 +3,7 @@
from collections import defaultdict
from odoo import api, models, registry
from odoo import api, models
NO_BI_MODELS = ["fetchmail.server"]
@ -212,25 +212,3 @@ class IrModel(models.Model):
)
fields_dict = list(map(dict_for_field, fields))
return fields_dict
@api.model
def create(self, vals):
if self.env.context and self.env.context.get("bve"):
vals["state"] = "base"
res = super().create(vals)
# this sql update is necessary since a write method here would
# be not working (an orm constraint is restricting the modification
# of the state field while updating ir.model)
q = "UPDATE ir_model SET state = 'manual' WHERE id = %s"
self.env.cr.execute(q, (res.id,))
# # update registry
if self.env.context.get("bve"):
# setup models; this reloads custom models in registry
self.pool.setup_models(self._cr)
# signal that registry has changed
registry(self.env.cr.dbname).signal_changes()
return res

1
bi_view_editor/models/models.py

@ -17,7 +17,6 @@ def _bi_view(_name):
_auto_init_orig = models.BaseModel._auto_init
@api.model_cr_context
def _auto_init(self):
# This monkey patch is meant to fix an error (probably

7
bi_view_editor/readme/USAGE.rst

@ -22,5 +22,8 @@ A more advanced UI is also available under the "Details" tab. It provides extra
possibilities for more advanced users, like to use LEFT JOIN instead of the
default INNER JOIN.
It also possible to improve the IDs generation for new views by adding an `Over Condition` in the "SQL" tab, see https://www.postgresql.org/docs/current/sql-expressions.html#SYNTAX-WINDOW-FUNCTIONS for further details.
For instance, an ORDER BY clause helps preventing unreliable behavior when filtering the generated views.
It also possible to improve the IDs generation for new views by adding an
`Over Condition` in the "SQL" tab, see https://www.postgresql.org/docs/current/sql-expressions.html#SYNTAX-WINDOW-FUNCTIONS
for further details.
For instance, an ORDER BY clause helps preventing unreliable behavior when
filtering the generated views.

5
bi_view_editor/static/src/css/bve.css

@ -159,11 +159,6 @@
width: 175px;
}
.oe_form_field_bi_editor .context-menu .checkbox {
margin-top: 0px;
margin-bottom: 0px;
}
.oe_form_field_bi_editor .context-menu .checkbox label {
display: block;
}

44
bi_view_editor/static/src/js/bi_view_editor.FieldList.js

@ -7,8 +7,10 @@ odoo.define("bi_view_editor.FieldList", function(require) {
var core = require("web.core");
var qweb = core.qweb;
var Widget = require("web.Widget");
var mixins = require("web.mixins");
var FieldListContextMenu = Widget.extend({
var FieldListContextMenu = Widget.extend(
_.extend({}, mixins.EventDispatcherMixin, {
start: function() {
var res = this._super.apply(this, arguments);
this.$el.mouseleave(function() {
@ -22,13 +24,15 @@ odoo.define("bi_view_editor.FieldList", function(require) {
top: y + "px",
});
this.$el.removeClass("d-none");
return _.extend({}, window.Backbone.Events);
return this;
},
});
})
);
var FieldListFieldContextMenu = FieldListContextMenu.extend({
template: "bi_view_editor.FieldList.FieldContextMenu",
open: function(x, y, field) {
open: function(x, y, $item) {
var field = $item.data("field");
this.$el.find(".checkbox-column").prop("checked", field.column);
this.$el.find(".checkbox-row").prop("checked", field.row);
this.$el.find(".checkbox-measure").prop("checked", field.measure);
@ -49,7 +53,7 @@ odoo.define("bi_view_editor.FieldList", function(require) {
var $checkbox = $(this);
var property = $checkbox.attr("data-for");
field[property] = $checkbox.is(":checked");
events.trigger("change", field);
events.trigger("change", field, $item);
});
return events;
@ -58,7 +62,8 @@ odoo.define("bi_view_editor.FieldList", function(require) {
var FieldListJoinContextMenu = FieldListContextMenu.extend({
template: "bi_view_editor.FieldList.JoinContextMenu",
open: function(x, y, node) {
open: function(x, y, $item) {
var node = $item.data("field");
this.$el.find(".checkbox-join-left").prop("checked", node.join_left);
var events = this._super(x, y, node);
@ -83,8 +88,26 @@ odoo.define("bi_view_editor.FieldList", function(require) {
var res = this._super.apply(this, arguments);
this.contextmenu = new FieldListFieldContextMenu(this);
this.contextmenu.appendTo(this.$el);
this.contextmenu.on(
"change",
this,
function(f, $item) {
$item.data("field", f);
this.refreshItem($item);
this.trigger("updated");
}.bind(this)
);
this.contextmenu_join = new FieldListJoinContextMenu(this);
this.contextmenu_join.appendTo(this.$el);
this.contextmenu_join.on(
"change",
this,
function(f, $item) {
$item.data("field", f);
this.refreshItem($item);
this.trigger("updated");
}.bind(this)
);
this.$table = this.$el.find("tbody");
this.mode = null;
return res;
@ -201,14 +224,7 @@ odoo.define("bi_view_editor.FieldList", function(require) {
if (field.join_node) {
return;
}
contextmenu.open(x - 20, y - 20, $item.data("field")).on(
"change",
function(f) {
$item.data("field", f);
this.refreshItem($item);
this.trigger("updated");
}.bind(this)
);
contextmenu.open(x - 20, y - 20, $item);
},
refreshItem: function($item) {
var data = $item.data("field");

4
bi_view_editor/static/src/js/bi_view_editor.ModelList.js

@ -80,7 +80,7 @@ odoo.define("bi_view_editor.ModelList", function(require) {
self.$el.find(".class-list").append($html);
if (self.isActive(model.id)) {
self.loadFields(model.id).done(function(fields) {
self.loadFields(model.id).then(function(fields) {
self.populateFields(fields, model.id);
});
}
@ -129,7 +129,7 @@ odoo.define("bi_view_editor.ModelList", function(require) {
this.removeAsActive(model.id);
} else {
this.addAsActive(model.id);
this.loadFields(model.id).done(
this.loadFields(model.id).then(
function(fields) {
this.populateFields(fields, model.id);
}.bind(this)

12
bi_view_editor/static/src/js/bi_view_editor.js

@ -30,10 +30,10 @@ odoo.define("bi_view_editor", function(require) {
// Init FieldList
this.field_list = new FieldList(this);
this.field_list.appendTo(this.$(".body > .right"));
this.field_list.appendTo(this.$(".body > .right")).then(
function() {
this.field_list.on("removed", this, this.fieldListRemoved);
this.field_list.on("updated", this, this.fieldListChanged);
this.$el.find(".body > .right").droppable({
accept: "div.class-list div.field",
drop: function(event, ui) {
@ -48,6 +48,9 @@ odoo.define("bi_view_editor", function(require) {
this.renderValue();
this.loadAndPopulateModelList();
this.updateMode();
}.bind(this)
);
return res;
},
clear: function() {
@ -61,10 +64,9 @@ odoo.define("bi_view_editor", function(require) {
this._setValue(this.field_list.get());
},
fieldListRemoved: function() {
console.log(this.field_list.get());
this._setValue(this.field_list.get());
var model = new Data.DataSet(this, "bve.view");
model.call("get_clean_list", [this.value]).then(
model.call("get_clean_list", [this.lastSetValue]).then(
function(result) {
this.field_list.set(JSON.parse(result));
this._setValue(this.field_list.get());
@ -91,7 +93,7 @@ odoo.define("bi_view_editor", function(require) {
if (this.field_list.get().length > 0) {
model_ids = this.field_list.getModelIds();
}
this.model_list.loadModels(model_ids).done(
this.model_list.loadModels(model_ids).then(
function(models) {
this.model_list.populateModels(models);
}.bind(this)

20
bi_view_editor/static/src/xml/bi_view_editor.xml

@ -120,18 +120,16 @@
type="checkbox"
data-for="column"
class="checkbox-column"
/> Column
/>
<span>Column</span>
</label>
</div>
</li>
<li>
<div class="checkbox">
<label>
<input
type="checkbox"
data-for="row"
class="checkbox-row"
/> Row
<input type="checkbox" data-for="row" class="checkbox-row" />
<span>Row</span>
</label>
</div>
</li>
@ -142,18 +140,16 @@
type="checkbox"
data-for="measure"
class="checkbox-measure"
/> Measure
/>
<span>Measure</span>
</label>
</div>
</li>
<li>
<div class="checkbox">
<label>
<input
type="checkbox"
data-for="list"
class="checkbox-list"
/> List
<input type="checkbox" data-for="list" class="checkbox-list" />
<span>List</span>
</label>
</div>
</li>

33
bi_view_editor/tests/test_bi_view.py

@ -8,7 +8,7 @@ from odoo.exceptions import UserError, ValidationError
from odoo.tests.common import TransactionCase
from odoo.tools import mute_logger
from ..hooks import post_load, uninstall_hook
from ..hooks import uninstall_hook
class TestBiViewEditor(TransactionCase):
@ -174,9 +174,7 @@ class TestBiViewEditor(TransactionCase):
def test_06_create_group_bve_object(self):
vals = self.bi_view1_vals
employees_group = self.env.ref("base.group_user")
vals.update(
{"name": "Test View2", "group_ids": [(6, 0, [employees_group.id])],}
)
vals.update({"name": "Test View2", "group_ids": [(6, 0, [employees_group.id])]})
bi_view2 = self.env["bve.view"].create(vals)
self.assertEqual(len(bi_view2.user_ids), len(employees_group.users))
@ -200,9 +198,7 @@ class TestBiViewEditor(TransactionCase):
def test_09_create_open_bve_object(self):
vals = self.bi_view1_vals
employees_group = self.env.ref("base.group_user")
vals.update(
{"name": "Test View4", "group_ids": [(6, 0, [employees_group.id])],}
)
vals.update({"name": "Test View4", "group_ids": [(6, 0, [employees_group.id])]})
bi_view = self.env["bve.view"].create(vals)
self.assertEqual(len(bi_view), 1)
self.assertEqual(len(bi_view.line_ids), 3)
@ -251,9 +247,7 @@ class TestBiViewEditor(TransactionCase):
@odoo.tests.tagged("post_install", "-at_install")
def test_10_create_open_bve_object_apostrophe(self):
vals = self.bi_view1_vals
vals.update(
{"name": "Test View5",}
)
vals.update({"name": "Test View5"})
data_list = list()
for r in json.loads(vals["data"]):
r["model_name"] = "model'name"
@ -310,9 +304,7 @@ class TestBiViewEditor(TransactionCase):
def test_12_check_groups(self):
vals = self.bi_view1_vals
group_system = self.env.ref("base.group_system")
vals.update(
{"name": "Test View1", "group_ids": [(6, 0, [group_system.id])],}
)
vals.update({"name": "Test View1", "group_ids": [(6, 0, [group_system.id])]})
bi_view1 = self.env["bve.view"].create(vals)
with self.assertRaises(UserError):
bi_view1.action_create()
@ -320,9 +312,7 @@ class TestBiViewEditor(TransactionCase):
def test_13_check_lines_missing_model(self):
vals = self.bi_view1_vals
group_user = self.env.ref("base.group_user")
vals.update(
{"name": "Test View1", "group_ids": [(6, 0, [group_user.id])],}
)
vals.update({"name": "Test View1", "group_ids": [(6, 0, [group_user.id])]})
bi_view1 = self.env["bve.view"].create(vals)
for line in bi_view1.line_ids:
self.assertTrue(line.model_id)
@ -338,9 +328,7 @@ class TestBiViewEditor(TransactionCase):
def test_14_check_lines_missing_fieldl(self):
vals = self.bi_view1_vals
group_user = self.env.ref("base.group_user")
vals.update(
{"name": "Test View1", "group_ids": [(6, 0, [group_user.id])],}
)
vals.update({"name": "Test View1", "group_ids": [(6, 0, [group_user.id])]})
bi_view1 = self.env["bve.view"].create(vals)
for line in bi_view1.line_ids:
self.assertTrue(line.field_id)
@ -362,9 +350,6 @@ class TestBiViewEditor(TransactionCase):
self.assertTrue(data)
self.assertTrue(isinstance(data, list))
def test_16_post_load(self):
post_load()
def test_17_uninstall_hook(self):
uninstall_hook(self.cr, self.env)
@ -419,9 +404,7 @@ class TestBiViewEditor(TransactionCase):
ERROR: bad_query line in the logs.
"""
vals = self.bi_view1_vals
vals.update(
{"name": "Test View broken", "over_condition": "bad SQL code",}
)
vals.update({"name": "Test View broken", "over_condition": "bad SQL code"})
bi_view = self.env["bve.view"].create(vals)
with self.assertRaises(UserError) as ue:
bi_view.action_create()

18
bi_view_editor/views/bve_view.xml

@ -1,19 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="action_bi_view_editor_translations" model="ir.actions.act_window">
<field name="name">Translations</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.translation</field>
<field name="view_type">form</field>
<field
name="domain"
>[('res_id', '=', active_record.), ('name', '=', 'ir.model.fields,field_description')]</field>
<field name="view_id" ref="base.view_translation_dialog_tree" />
</record>
<record id="view_bi_view_editor_view_tree" model="ir.ui.view">
<field name="model">bve.view</field>
<field name="arch" type="xml">
<tree string="Custom BI View">
<tree>
<field name="name" />
</tree>
</field>
@ -21,7 +11,7 @@
<record id="view_bi_view_editor_view_form" model="ir.ui.view">
<field name="model">bve.view</field>
<field name="arch" type="xml">
<form string="Custom Object">
<form>
<header>
<button
name="action_reset"
@ -108,6 +98,7 @@
<tree
editable="bottom"
decoration-muted="in_list == False"
create="false"
>
<field name="sequence" widget="handle" />
<field name="description" string="Field" />
@ -142,7 +133,7 @@
name="relation_ids"
attrs="{'readonly': [('state','=','created')]}"
>
<tree editable="bottom">
<tree editable="bottom" create="false">
<field name="sequence" widget="handle" />
<field name="description" string="Field" />
<field name="model_id" readonly="1" />
@ -177,7 +168,6 @@
<record id="action_bi_view_editor_view_form" model="ir.actions.act_window">
<field name="name">Custom BI Views</field>
<field name="res_model">bve.view</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">

Loading…
Cancel
Save