diff --git a/web_timeline/README.rst b/web_timeline/README.rst index a7a3e58cdd2..4bd26593a01 100644 --- a/web_timeline/README.rst +++ b/web_timeline/README.rst @@ -2,7 +2,7 @@ Web timeline ============ -.. +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! @@ -257,7 +257,7 @@ promote its widespread use. Current `maintainer `__: -|maintainer-tarteo| +|maintainer-tarteo| This module is part of the `OCA/web `_ project on GitHub. diff --git a/web_timeline/static/description/index.html b/web_timeline/static/description/index.html index 1795f37ac77..0266e44233f 100644 --- a/web_timeline/static/description/index.html +++ b/web_timeline/static/description/index.html @@ -8,11 +8,10 @@ /* :Author: David Goodger (goodger@python.org) -:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $ +:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. -Despite the name, some widely supported CSS2 features are used. See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to customize this style sheet. @@ -275,7 +274,7 @@ margin-left: 2em ; margin-right: 2em } -pre.code .ln { color: gray; } /* line numbers */ +pre.code .ln { color: grey; } /* line numbers */ pre.code, code { background-color: #eeeeee } pre.code .comment, code .comment { color: #5C6576 } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } @@ -301,7 +300,7 @@ span.pre { white-space: pre } -span.problematic, pre.problematic { +span.problematic { color: red } span.section-subtitle { @@ -614,9 +613,7 @@

Contributors

Maintainers

This module is maintained by the OCA.

- -Odoo Community Association - +Odoo Community Association

OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

diff --git a/web_timeline/static/src/js/timeline_controller.esm.js b/web_timeline/static/src/js/timeline_controller.esm.js index 98e05cf56be..bc5344ad8a3 100644 --- a/web_timeline/static/src/js/timeline_controller.esm.js +++ b/web_timeline/static/src/js/timeline_controller.esm.js @@ -93,15 +93,19 @@ export default AbstractController.extend({ */ _onGroupClick: function (event) { const groupField = this.renderer.last_group_bys[0]; - return this.do_action({ - type: "ir.actions.act_window", - res_model: this.renderer.fields[groupField].relation, - res_id: event.data.item.group, - target: "new", - views: [[false, "form"]], - }); + const field = this.renderer.fields[groupField]; + if (field.relation) { + return this.do_action({ + type: "ir.actions.act_window", + res_model: field.relation, + res_id: event.data.item.group, + target: "new", + views: [[false, "form"]], + }); + } + console.warn(`Field ${groupField} is not a relational field.`); + return $.Deferred().resolve(); }, - /** * Triggered on double-click on an item in read-only mode (otherwise, we use _onUpdate). * diff --git a/web_timeline/static/src/js/timeline_renderer.js b/web_timeline/static/src/js/timeline_renderer.js index aba23f76039..14e8bdfe1d4 100644 --- a/web_timeline/static/src/js/timeline_renderer.js +++ b/web_timeline/static/src/js/timeline_renderer.js @@ -380,66 +380,80 @@ odoo.define("web_timeline.TimelineRenderer", function (require) { * @returns {Array} */ split_groups: async function (events, group_bys) { - if (group_bys.length === 0) { - return events; - } - const groups = []; - groups.push({id: -1, content: _t("UNASSIGNED"), order: -1}); - var seq = 1; + if (group_bys.length === 0) return events; + + const groups = [{id: -1, content: _t("UNASSIGNED"), order: -1}]; + const grouped_field = _.first(group_bys); + const fieldType = this.fields[grouped_field].type; + const relation = this.fields[grouped_field].relation; + const groupIds = new Set(); for (const evt of events) { - const grouped_field = _.first(group_bys); const group_name = evt[grouped_field]; if (group_name) { if (group_name instanceof Array) { - const group = _.find( - groups, - (existing_group) => existing_group.id === group_name[0] - ); - if (_.isUndefined(group)) { - // Check if group is m2m in this case add id -> value of all - // found entries. - await this._rpc({ - model: this.modelName, - method: "fields_get", - args: [[grouped_field]], - context: this.getSession().user_context, - }).then(async (fields) => { - if (fields[grouped_field].type === "many2many") { - const list_values = - await this.get_m2m_grouping_datas( - fields[grouped_field].relation, - group_name - ); - for (const vals of list_values) { - let is_inside = false; - for (const gr of groups) { - if (vals.id === gr.id) { - is_inside = true; - break; - } - } - if (!is_inside) { - vals.order = seq; - seq += 1; - groups.push(vals); - } - } - } else { - groups.push({ - id: group_name[0], - content: group_name[1], - order: seq, - }); - seq += 1; - } - }); - } + groupIds.add(group_name[0]); + } else { + groupIds.add(group_name); + } + } + } + const idToOrder = {}; + if (groupIds.size > 0 && relation) { + const relatedRecords = await this._rpc({ + model: relation, + method: "search_read", + args: [[["id", "in", Array.from(groupIds)]]], + context: this.getSession().user_context, + }); + relatedRecords.forEach((record, index) => { + idToOrder[record.id] = index + 1; + }); + } + + for (const evt of events) { + const group_name = evt[grouped_field]; + if (!group_name) continue; + + const group_id = + group_name instanceof Array ? group_name[0] : group_name; + const group_content = + group_name instanceof Array ? group_name[1] : group_name; + + const group = _.find( + groups, + (existing_group) => existing_group.id === group_id + ); + if (group) continue; + + if (fieldType !== "many2one" && fieldType !== "many2many") { + groups.push({ + id: group_id, + content: group_content, + order: idToOrder[group_id] || groups.length, + }); + continue; + } + + if (fieldType === "many2one") { + groups.push({ + id: group_id, + content: group_content, + order: idToOrder[group_id] || groups.length, + }); + } else if (fieldType === "many2many") { + const list_values = await this.get_m2m_grouping_datas( + relation, + group_name + ); + for (const vals of list_values) { + if (groups.some((gr) => gr.id === vals.id)) continue; + vals.order = idToOrder[vals.id] || groups.length; + groups.push(vals); } } } return groups; }, - get_m2m_grouping_datas: async function (model, group_name) { const groups = []; for (const gr of group_name) { @@ -507,12 +521,13 @@ odoo.define("web_timeline.TimelineRenderer", function (require) { event_data_transform: function (evt) { const [date_start, date_stop] = this._get_event_dates(evt); let group = evt[this.last_group_bys[0]]; - if (group && group instanceof Array && group.length > 0) { - group = _.first(group); + if (group) { + if (group instanceof Array && group.length > 0) { + group = _.first(group); + } } else { group = -1; } - for (const color of this.colors) { if (py.eval(`'${evt[color.field]}' ${color.opt} '${color.value}'`)) { this.color = color.color;