Skip to content

Commit 8829e9f

Browse files
committed
[MIG] bi_view_editor: migration to 16.0
1 parent 0913196 commit 8829e9f

30 files changed

+1115
-1068
lines changed

bi_view_editor/__manifest__.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
"license": "AGPL-3",
1010
"website": "https://github.com/OCA/reporting-engine",
1111
"category": "Productivity",
12-
"version": "15.0.1.0.0",
12+
"version": "16.0.1.0.0",
1313
"development_status": "Beta",
14-
"depends": ["web"],
14+
"depends": [
15+
"web",
16+
],
1517
"external_dependencies": {
1618
"deb": ["graphviz"],
1719
},
@@ -22,16 +24,8 @@
2224
],
2325
"assets": {
2426
"web.assets_backend": [
25-
"bi_view_editor/static/src/css/bve.css",
26-
"bi_view_editor/static/src/js/bi_view_editor.js",
27-
"bi_view_editor/static/src/js/bi_view_editor.JoinNodeDialog.js",
28-
"bi_view_editor/static/src/js/bi_view_editor.ModelList.js",
29-
"bi_view_editor/static/src/js/bi_view_editor.FieldList.js",
30-
],
31-
"web.assets_qweb": [
32-
"bi_view_editor/static/src/xml/bi_view_editor.xml",
27+
"bi_view_editor/static/src/components/**/*",
3328
],
3429
},
3530
"uninstall_hook": "uninstall_hook",
36-
"installable": True,
3731
}

bi_view_editor/models/bve_view.py

Lines changed: 5 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def _inverse_serialized_data(self):
6060
line_ids = self._sync_lines_and_data(bve_view.data)
6161
bve_view.write({"line_ids": line_ids})
6262

63-
name = fields.Char(required=True, copy=False, default="")
63+
name = fields.Char(required=True, copy=False, translate=True)
6464
model_name = fields.Char(compute="_compute_model_name", store=True)
6565
note = fields.Text(string="Notes")
6666
state = fields.Selection(
@@ -388,35 +388,6 @@ def _compute_sql_query(self):
388388
AsIs(from_str),
389389
)
390390

391-
def action_translations(self):
392-
self.ensure_one()
393-
if self.state != "created":
394-
return
395-
self = self.sudo()
396-
model = self.env["ir.model"].sudo().search([("model", "=", self.model_name)])
397-
IrTranslation = self.env["ir.translation"]
398-
IrTranslation.translate_fields("ir.model", model.id)
399-
for field in model.field_id:
400-
IrTranslation.translate_fields("ir.model.fields", field.id)
401-
return {
402-
"name": "Translations",
403-
"res_model": "ir.translation",
404-
"type": "ir.actions.act_window",
405-
"view_mode": "tree",
406-
"view_id": self.env.ref("base.view_translation_dialog_tree").id,
407-
"target": "current",
408-
"flags": {"search_view": True, "action_buttons": True},
409-
"domain": [
410-
"|",
411-
"&",
412-
("res_id", "in", model.field_id.ids),
413-
("name", "=", "ir.model.fields,field_description"),
414-
"&",
415-
("res_id", "=", model.id),
416-
("name", "=", "ir.model,name"),
417-
],
418-
}
419-
420391
def action_create(self):
421392
self.ensure_one()
422393

@@ -441,7 +412,10 @@ def action_create(self):
441412
"name": self.name,
442413
"model": self.model_name,
443414
"state": "manual",
444-
"field_id": [(0, 0, f) for f in bve_fields._prepare_field_vals()],
415+
"field_id": [
416+
fields.Command.create(f)
417+
for f in bve_fields._prepare_field_vals()
418+
],
445419
}
446420
)
447421
)

bi_view_editor/models/bve_view_line.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,16 @@ def _prepare_field_vals(self):
101101
"complete_name": field.complete_name,
102102
"model": line.bve_view_id.model_name,
103103
"relation": field.relation,
104+
# FIXME: this sets the en_US value from the current language's
105+
# translation. instead, all translations should be set with
106+
# their corresponding value.
104107
"field_description": line.description,
105108
"ttype": field.ttype,
106109
"selection": field.selection,
107110
"size": field.size,
108111
"state": "manual",
109112
"readonly": True,
113+
"translate": field.translate,
110114
"groups": [(6, 0, field.groups.ids)],
111115
}
112116
if vals["ttype"] == "monetary":

bi_view_editor/models/ir_model.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ def get_fields(self, model_id):
212212
("name", "not in", models.MAGIC_COLUMNS),
213213
("ttype", "not in", NO_BI_TTYPES),
214214
],
215-
order="field_description desc",
215+
order="field_description",
216216
)
217217
)
218218
fields_dict = list(map(dict_for_field, fields))

bi_view_editor/readme/CONTRIBUTORS.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@
77
* Antonio Esposito <[email protected]>
88
* Jordi Ballester Alomar <[email protected]>
99
* Italo LOPES <[email protected]>
10+
* `Coop IT Easy SC <https://coopiteasy.be>`_:
11+
12+
* hugues de keyzer

bi_view_editor/readme/ROADMAP.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@
55
* Data the user has no access to (e.g. in a multi company situation) can be
66
viewed by making a view. Would be nice if models available to select when
77
creating a view are limited to the ones that have intersecting groups.
8+
* As of Odoo 16, translations of the name of a BI View and of the field
9+
descriptions do not work as expected: the translated strings are selected
10+
(by the user's language) when the view is generated (and stored as their
11+
``en_US`` value) instead of when it is displayed.

bi_view_editor/static/src/css/bve.css renamed to bi_view_editor/static/src/components/bi_view_editor/bi_view_editor.css

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,19 @@
9191
}
9292

9393
.oe_form_field_bi_editor .body .left .class-list .class.readonly {
94-
cursor: default;
94+
cursor: inherit;
9595
}
9696

9797
.oe_form_field_bi_editor .body .left .class-list .class:hover {
9898
background-color: #7c7bad;
9999
color: #fff;
100100
}
101101

102+
.oe_form_field_bi_editor .body .left .class-list .class.readonly:hover {
103+
background-color: inherit;
104+
color: inherit;
105+
}
106+
102107
.oe_form_field_bi_editor .body .left .class-list .field {
103108
font-weight: normal;
104109
padding-left: 20px;
@@ -134,13 +139,16 @@
134139
border: none;
135140
background-image: none;
136141
padding: 0;
137-
cursor: pointer;
138142
}
139143

140144
.oe_form_field_bi_editor .body .right .field-list tbody tr:hover {
141145
background-color: #ddd;
142146
}
143147

148+
.oe_form_field_bi_editor .body .right .field-list tbody tr.readonly:hover {
149+
background-color: inherit;
150+
}
151+
144152
.oe_form_field_bi_editor .body .right .field-list tbody tr.join-node {
145153
background-color: #d2d2ff;
146154
text-align: center;
@@ -196,3 +204,7 @@
196204
.oe_bi_view_editor_join_node_dialog li {
197205
cursor: pointer;
198206
}
207+
208+
.o_field_widget.o_field_BVEEditor {
209+
width: 100%;
210+
}
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
/** @odoo-module **/
2+
3+
/* Copyright 2015-2019 Onestein (<https://www.onestein.eu>)
4+
* License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). */
5+
6+
import {Component, onWillUpdateProps, useState} from "@odoo/owl";
7+
import {FIELD_DATA_TYPE, ModelList} from "./model_list.esm";
8+
import {FieldList} from "./field_list.esm";
9+
import {JoinNodeDialog} from "./join_node_dialog.esm";
10+
import {registry} from "@web/core/registry";
11+
import {standardFieldProps} from "@web/views/fields/standard_field_props";
12+
import {useService} from "@web/core/utils/hooks";
13+
14+
export class BiViewEditor extends Component {
15+
setup() {
16+
this.state = useState({
17+
models: [],
18+
fields: [],
19+
// This allows to access fields by their _id property in an
20+
// efficient way. Since the fields array length is normally quite
21+
// small, it would also be possible to use
22+
// fields.find(element => element._id == field._id), but that
23+
// would mean that this function would be defined in 3 places
24+
// (deleteField(), setFieldProperty() and
25+
// FieldList.setFieldProperty()), and using a common function
26+
// would be quite similar to using this object.
27+
fieldsByID: {},
28+
});
29+
this.orm = useService("orm");
30+
this.dialogService = useService("dialog");
31+
onWillUpdateProps((nextProps) => {
32+
this.updateFields(nextProps.value);
33+
});
34+
this.updateFields(this.props.value);
35+
}
36+
get modelIDs() {
37+
const model_ids = {};
38+
for (const field of this.state.fields) {
39+
model_ids[field.table_alias] = field.model_id;
40+
}
41+
return model_ids;
42+
}
43+
get modelData() {
44+
const model_data = {};
45+
for (const field of this.state.fields) {
46+
model_data[field.table_alias] = {
47+
model_id: field.model_id,
48+
model_name: field.model_name,
49+
};
50+
}
51+
return model_data;
52+
}
53+
_addField(field) {
54+
field.row = typeof field.row === "undefined" ? false : field.row;
55+
field.column = typeof field.column === "undefined" ? false : field.column;
56+
field.measure = typeof field.measure === "undefined" ? false : field.measure;
57+
field.list = typeof field.list === "undefined" ? true : field.list;
58+
field._id = typeof field._id === "undefined" ? _.uniqueId("node_") : field._id;
59+
if (field.join_node) {
60+
field.join_left =
61+
typeof field.join_left === "undefined" ? false : field.join_left;
62+
}
63+
64+
let i = 0;
65+
const name = field.name;
66+
while (
67+
this.state.fields.filter(function (item) {
68+
return item.name === field.name;
69+
}).length > 0
70+
) {
71+
field.name = name + "_" + i;
72+
i++;
73+
}
74+
this.state.fields.push(field);
75+
this.state.fieldsByID[field._id] = field;
76+
}
77+
deleteField(field) {
78+
this.state.fields.splice(
79+
this.state.fields.findIndex((element) => {
80+
return element._id === field._id;
81+
}),
82+
1
83+
);
84+
delete this.state.fieldsByID[field._id];
85+
this.fieldDeleted();
86+
}
87+
setFieldProperty(field, property, value) {
88+
this.state.fieldsByID[field._id][property] = value;
89+
this.fieldUpdated();
90+
}
91+
setFields(fields) {
92+
this.state.fields = [];
93+
this.state.fieldsByID = {};
94+
for (const field of fields) {
95+
this._addField(field);
96+
}
97+
}
98+
updateFields(value) {
99+
if (value) {
100+
this.setFields(JSON.parse(value));
101+
}
102+
this.updateModels();
103+
}
104+
updateModels() {
105+
const model_ids = this.modelIDs;
106+
this.orm
107+
.call("ir.model", "get_models", model_ids ? [model_ids] : [])
108+
.then((models) => {
109+
this.state.models = models;
110+
});
111+
}
112+
clear() {
113+
if (this.props.readonly) {
114+
return;
115+
}
116+
this.setFields([]);
117+
this.updateValue();
118+
}
119+
fieldUpdated() {
120+
this.updateValue();
121+
}
122+
fieldDeleted() {
123+
this.orm
124+
.call("bve.view", "get_clean_list", [this.state.fields])
125+
.then((result) => {
126+
this.updateFields(result);
127+
this.updateValue();
128+
});
129+
}
130+
getTableAlias(field) {
131+
if (typeof field.table_alias === "undefined") {
132+
const model_ids = this.modelIDs;
133+
let n = 1;
134+
while (typeof model_ids["t" + n] !== "undefined") {
135+
n++;
136+
}
137+
return "t" + n;
138+
}
139+
return field.table_alias;
140+
}
141+
addFieldAndJoinNode(field, join_node) {
142+
if (join_node.join_node === -1 || join_node.table_alias === -1) {
143+
field.table_alias = this.getTableAlias(field);
144+
if (join_node.join_node === -1) {
145+
join_node.join_node = field.table_alias;
146+
} else {
147+
join_node.table_alias = field.table_alias;
148+
}
149+
this._addField(join_node);
150+
} else {
151+
field.table_alias = join_node.table_alias;
152+
}
153+
154+
this._addField(field);
155+
this.updateValue();
156+
}
157+
addField(field) {
158+
const data = _.extend({}, field);
159+
const field_data = this.state.fields;
160+
this.orm
161+
.call("ir.model", "get_join_nodes", [field_data, data])
162+
.then((result) => {
163+
if (result.length === 1) {
164+
this.addFieldAndJoinNode(data, result[0]);
165+
} else if (result.length > 1) {
166+
this.dialogService.add(JoinNodeDialog, {
167+
choices: result,
168+
model_data: this.modelData,
169+
choiceSelected: (choice) => {
170+
this.addFieldAndJoinNode(data, choice);
171+
},
172+
});
173+
} else {
174+
data.table_alias = this.getTableAlias(data);
175+
this._addField(data);
176+
this.updateValue();
177+
}
178+
});
179+
}
180+
fieldClicked(field) {
181+
this.addField(field);
182+
}
183+
onDragOver(e) {
184+
if (this.props.readonly) {
185+
return;
186+
}
187+
const dragType = e.dataTransfer.types[0];
188+
if (dragType === FIELD_DATA_TYPE) {
189+
e.preventDefault();
190+
e.dataTransfer.dropEffect = "copy";
191+
}
192+
}
193+
onDrop(e) {
194+
if (this.props.readonly) {
195+
return;
196+
}
197+
const dragData = e.dataTransfer.getData(FIELD_DATA_TYPE);
198+
if (dragData) {
199+
e.preventDefault();
200+
this.addField(JSON.parse(dragData));
201+
}
202+
}
203+
updateValue() {
204+
this.props.update(JSON.stringify(this.state.fields));
205+
this.updateModels();
206+
}
207+
}
208+
BiViewEditor.template = "bi_view_editor.Frame";
209+
BiViewEditor.components = {
210+
ModelList,
211+
FieldList,
212+
};
213+
BiViewEditor.props = {
214+
...standardFieldProps,
215+
};
216+
217+
registry.category("fields").add("BVEEditor", BiViewEditor);

0 commit comments

Comments
 (0)