bemade_hierarchical_tree_view: initial work adding parent/child hierarchy by extending Odoo's list view.
This commit is contained in:
parent
0f035bb86b
commit
aa6b0f917f
5 changed files with 244 additions and 0 deletions
62
bemade_hierarchical_tree_view/rng/hlist.rng
Normal file
62
bemade_hierarchical_tree_view/rng/hlist.rng
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<rng:grammar xmlns:rng="http://relaxng.org/ns/structure/1.0"
|
||||||
|
xmlns:a="http://relaxng.org/ns/annotation/1.0"
|
||||||
|
datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
|
||||||
|
<!-- Handling of element overloading when inheriting from a base
|
||||||
|
template
|
||||||
|
-->
|
||||||
|
|
||||||
|
<rng:define name="hlist">
|
||||||
|
<rng:element name="hlist">
|
||||||
|
<rng:attribute name="parent_field"/>
|
||||||
|
<rng:optional><rng:attribute name="name"/></rng:optional>
|
||||||
|
<rng:optional><rng:attribute name="create"/></rng:optional>
|
||||||
|
<rng:optional><rng:attribute name="delete"/></rng:optional>
|
||||||
|
<rng:optional><rng:attribute name="edit"/></rng:optional>
|
||||||
|
<rng:optional><rng:attribute name="multi_edit"/></rng:optional>
|
||||||
|
<rng:optional><rng:attribute name="export_xlsx"/></rng:optional>
|
||||||
|
<rng:optional><rng:attribute name="duplicate"/></rng:optional>
|
||||||
|
<rng:optional><rng:attribute name="import"/></rng:optional>
|
||||||
|
<rng:optional><rng:attribute name="string"/></rng:optional> <!-- deprecated, has no effect anymore -->
|
||||||
|
<rng:optional><rng:attribute name="class"/></rng:optional>
|
||||||
|
<!-- Allows to take a custom View widget for handling -->
|
||||||
|
<rng:optional><rng:attribute name="js_class"/></rng:optional>
|
||||||
|
<rng:optional><rng:attribute name="default_order"/></rng:optional>
|
||||||
|
<rng:optional><rng:attribute name="decoration-bf"/></rng:optional>
|
||||||
|
<rng:optional><rng:attribute name="decoration-it"/></rng:optional>
|
||||||
|
<rng:optional><rng:attribute name="decoration-danger"/></rng:optional>
|
||||||
|
<rng:optional><rng:attribute name="decoration-info"/></rng:optional>
|
||||||
|
<rng:optional><rng:attribute name="decoration-muted"/></rng:optional>
|
||||||
|
<rng:optional><rng:attribute name="decoration-primary"/></rng:optional>
|
||||||
|
<rng:optional><rng:attribute name="decoration-success"/></rng:optional>
|
||||||
|
<rng:optional><rng:attribute name="decoration-warning"/></rng:optional>
|
||||||
|
<rng:optional><rng:attribute name="banner_route"/></rng:optional>
|
||||||
|
<rng:optional><rng:attribute name="sample"/></rng:optional>
|
||||||
|
<rng:optional>
|
||||||
|
<rng:attribute name="limit">
|
||||||
|
<rng:data type="int"/>
|
||||||
|
</rng:attribute>
|
||||||
|
</rng:optional>
|
||||||
|
<rng:optional>
|
||||||
|
<rng:attribute name="groups_limit">
|
||||||
|
<rng:data type="int"/>
|
||||||
|
</rng:attribute>
|
||||||
|
</rng:optional>
|
||||||
|
<rng:optional>
|
||||||
|
<rng:attribute name="editable">
|
||||||
|
<rng:choice>
|
||||||
|
<rng:value>top</rng:value>
|
||||||
|
<rng:value>bottom</rng:value>
|
||||||
|
</rng:choice>
|
||||||
|
</rng:attribute>
|
||||||
|
</rng:optional>
|
||||||
|
</rng:element>
|
||||||
|
</rng:define>
|
||||||
|
|
||||||
|
<rng:start>
|
||||||
|
<rng:choice>
|
||||||
|
<rng:ref name="hlist"/>
|
||||||
|
</rng:choice>
|
||||||
|
</rng:start>
|
||||||
|
|
||||||
|
</rng:grammar>
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
/** @odoo-module alias=htree.HListController **/
|
||||||
|
|
||||||
|
import ListController from 'web.ListController';
|
||||||
|
|
||||||
|
var HListController = ListController.extend({
|
||||||
|
custom_events: _.extend({}, ListController.prototype.custom_events, {
|
||||||
|
toggle_hierarchy: '_onToggleHierarchy'
|
||||||
|
}),
|
||||||
|
init: function(parent, model, renderer, params) {
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
},
|
||||||
|
_onToggleHierarchy: function(ev) {
|
||||||
|
|
||||||
|
},
|
||||||
|
})
|
||||||
80
bemade_hierarchical_tree_view/static/src/js/hlist_model.js
Normal file
80
bemade_hierarchical_tree_view/static/src/js/hlist_model.js
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
/** @odoo-module alias=htree.HListModel **/
|
||||||
|
|
||||||
|
import ListModel from 'web.ListModel'
|
||||||
|
|
||||||
|
var HListModel = ListModel.extend({
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
* @param {string} params.parentField
|
||||||
|
*/
|
||||||
|
init: function (parent, params) {
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
this.parentField = params.parentField;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @override
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_readGroup: function (list, options) {
|
||||||
|
var self = this;
|
||||||
|
return this._super(list, options).then(function (result) {
|
||||||
|
return self._readHierarchy(list).then(_.constant(result));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Fetches hierarchy specific fields on the parent field relation and stores them
|
||||||
|
* in the column datapoint in a special key 'hierarchyData'.
|
||||||
|
* Data for the hierarchy are fetched in batch for all hierarchies, to avoid
|
||||||
|
* multiple calls.
|
||||||
|
*
|
||||||
|
* @param {Object} list
|
||||||
|
* @private
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
_readHierarchy (list) {
|
||||||
|
const self = this;
|
||||||
|
const parentFieldName = self.parentField;
|
||||||
|
const parentField = list.fields[parentFieldName];
|
||||||
|
/* Each record should have only one parent */
|
||||||
|
if (parentField.type !== 'many2one') {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
const hierarchyIds = _.reduce(list.data, function (hierarchyIds, id) {
|
||||||
|
const resId = self.get(id, { raw: true }).res_id;
|
||||||
|
if (resId) {
|
||||||
|
hierarchyIds.push(resId);
|
||||||
|
}
|
||||||
|
return hierarchyIds;
|
||||||
|
}, []);
|
||||||
|
let prom;
|
||||||
|
if (hierarchyIds.length) {
|
||||||
|
prom = this._rpc({
|
||||||
|
model: list.model,
|
||||||
|
method: 'read',
|
||||||
|
args: [hierarchyIds, self.viewFields],
|
||||||
|
context: list.context,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve(prom).then(function (result) {
|
||||||
|
_.each(list.data, function(id) {
|
||||||
|
let dp = self.localData[id];
|
||||||
|
let hierarchyData = result && _.findWhere(result, {
|
||||||
|
id: dp.res_id,
|
||||||
|
});
|
||||||
|
let hierarchyDp = self._makeDataPoint({
|
||||||
|
context: dp.context,
|
||||||
|
data: hierarchyData,
|
||||||
|
fields: list.fields,
|
||||||
|
fieldsInfo: list.fieldsInfo,
|
||||||
|
modelName: list.model,
|
||||||
|
parentID: dp.id,
|
||||||
|
res_id: dp.res_id,
|
||||||
|
viewType: 'list',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export default HListModel;
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
/** @odoo-module alias=htree.HListRenderer **/
|
||||||
|
|
||||||
|
import {ListRenderer} from 'web.ListRenderer'
|
||||||
|
|
||||||
|
var HierarchicalListRenderer = ListRenderer.extend({
|
||||||
|
className: 'o_hlist_view',
|
||||||
|
events: _.extend({}, ListRenderer.prototype.events, {
|
||||||
|
'click .o_hierarchy_parent': '_onToggleHierarchyGroup',
|
||||||
|
}),
|
||||||
|
init: function (parent, state, params) {
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
},
|
||||||
|
_renderBody: function () {
|
||||||
|
this._super.apply(this);
|
||||||
|
|
||||||
|
},
|
||||||
|
_renderHierarchy(data, hierarchyLevel) {
|
||||||
|
var self = this;
|
||||||
|
hierarchyLevel = hierarchyLevel || 0;
|
||||||
|
var result = [];
|
||||||
|
var $tbody = $('<tbody>');
|
||||||
|
_.each(data, function (hierarchyGroup) {
|
||||||
|
if (!$tbody) {
|
||||||
|
$tbody = $('<tbody>');
|
||||||
|
}
|
||||||
|
$tbody.append(self._renderHierarchyRow(hierarchyGroup, hierarchyLevel));
|
||||||
|
if (hierarchyGroup.data.length) {
|
||||||
|
result.push($tbody);
|
||||||
|
result = result.concat(self._renderHierarchyParent(hierarchyGroup,
|
||||||
|
hierarchyLevel));
|
||||||
|
$tbody = null;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
_renderHierarchyParent(hierarchyGroup, hierarchyLevel) {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
49
bemade_hierarchical_tree_view/static/src/js/hlist_view.js
Normal file
49
bemade_hierarchical_tree_view/static/src/js/hlist_view.js
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
/** @odoo-module alias=htree.HListView **/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Hierarchical List view extends the base List View from Odoo by adding
|
||||||
|
* a toggle to expand/collapse a hierarchy of records with children.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ListView from 'web.ListView';
|
||||||
|
import viewRegistry from 'web.view_registry';
|
||||||
|
import HListRenderer from 'htree.HListRenderer';
|
||||||
|
import HListController from 'htree.HListController';
|
||||||
|
import HListModel from 'htree.HListModel';
|
||||||
|
|
||||||
|
|
||||||
|
var HListView = ListView.extend({
|
||||||
|
accesskey: 't',
|
||||||
|
icon: 'fa-sitemap',
|
||||||
|
display_name: _lt("Hierarchical Tree"),
|
||||||
|
config: _.extend({}, ListView.prototype.config, {
|
||||||
|
Model: HListModel,
|
||||||
|
Controller: HListController,
|
||||||
|
Renderer: HListRenderer,
|
||||||
|
}),
|
||||||
|
viewType: 'hlist',
|
||||||
|
/**
|
||||||
|
* Add a parentField parameter to allow for hierarchy display.
|
||||||
|
*
|
||||||
|
* @override
|
||||||
|
*
|
||||||
|
* @param {Object} viewInfo
|
||||||
|
* @param {Object} params
|
||||||
|
* @param {boolean} params.hasActionMenus
|
||||||
|
* @param {string} [params.parentField]
|
||||||
|
* @param {boolean} [params.hasSelectors=true]
|
||||||
|
*/
|
||||||
|
init: function(viewInfo, params) {
|
||||||
|
var self = this;
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
this.parentField = params.parentField
|
||||||
|
},
|
||||||
|
_updateMVCParams: function() {
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
var attrs = this.arch.attrs;
|
||||||
|
this.loadParams.parentField = attrs.parentField;
|
||||||
|
this.modelParams.parentField = attrs.parentField;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
viewRegistry.add('hlist', HListView);
|
||||||
Loading…
Reference in a new issue