mirror of https://github.com/OCA/web.git
[IMP] web_timeline: Several improvements:
* Avoid to display all items of group_by model * Remove unnecessary readgroup * Remove dependency on project. Modify module structure. Imporve readme file. * Add setup.pypull/2969/head
parent
271b09d524
commit
a1ef8257c5
|
@ -1,7 +1,80 @@
|
||||||
|
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
|
||||||
|
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
|
||||||
|
:alt: License: AGPL-3
|
||||||
|
|
||||||
|
===============
|
||||||
Timeline Widget
|
Timeline Widget
|
||||||
===============
|
===============
|
||||||
|
|
||||||
!Prototype!
|
|
||||||
Define a new widget displaying events in an interactive visualization chart.
|
Define a new widget displaying events in an interactive visualization chart.
|
||||||
|
|
||||||
The widget is based on the external library
|
The widget is based on the external library
|
||||||
http://visjs.org/timeline_examples.html
|
http://visjs.org/timeline_examples.html
|
||||||
|
|
||||||
|
Usage
|
||||||
|
=====
|
||||||
|
|
||||||
|
Example:
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<openerp>
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<record id="view_task_timeline" model="ir.ui.view">
|
||||||
|
<field name="name">project.task.timeline</field>
|
||||||
|
<field name="model">project.task</field>
|
||||||
|
<field name="type">timeline</field>
|
||||||
|
<field eval="2" name="priority"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<timeline date_start="date_start"
|
||||||
|
date_stop="date_end"
|
||||||
|
date_delay='1'
|
||||||
|
string="Tasks"
|
||||||
|
default_group_by="user_id" event_open_popup="true" colors="#ec7063:user_id == false;#2ecb71:kanban_state=='done';">
|
||||||
|
</timeline>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="project.action_view_task" model="ir.actions.act_window">
|
||||||
|
<field name="view_mode">kanban,tree,form,calendar,gantt,timeline,graph</field>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</openerp>
|
||||||
|
|
||||||
|
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
|
||||||
|
:alt: Try me on Runbot
|
||||||
|
:target: https://runbot.odoo-community.org/runbot/162/8.0
|
||||||
|
|
||||||
|
Bug Tracker
|
||||||
|
===========
|
||||||
|
|
||||||
|
Bugs are tracked on `GitHub Issues
|
||||||
|
<https://github.com/OCA/web/issues>`_. In case of trouble, please
|
||||||
|
check there if your issue has already been reported. If you spotted it first,
|
||||||
|
help us smashing it by providing a detailed and welcomed feedback.
|
||||||
|
|
||||||
|
Credits
|
||||||
|
=======
|
||||||
|
|
||||||
|
Images
|
||||||
|
------
|
||||||
|
|
||||||
|
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.
|
||||||
|
|
||||||
|
Contributors
|
||||||
|
------------
|
||||||
|
|
||||||
|
* Laurent Mignon <laurent.mignon@acsone.eu>
|
||||||
|
* Adrien Peiffer <adrien.peiffer@acsone.eu>
|
||||||
|
|
||||||
|
Maintainer
|
||||||
|
----------
|
||||||
|
|
||||||
|
.. image:: https://odoo-community.org/logo.png
|
||||||
|
:alt: Odoo Community Association
|
||||||
|
:target: https://odoo-community.org
|
||||||
|
|
||||||
|
This module is maintained by the OCA.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
To contribute to this module, please visit https://odoo-community.org.
|
|
@ -1 +1,5 @@
|
||||||
from . import ir_view
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2016 ACSONE SA/NV (<http://acsone.eu>)
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
|
|
||||||
|
from . import models
|
||||||
|
|
|
@ -1,16 +1,24 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2016 ACSONE SA/NV (<http://acsone.eu>)
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
|
|
||||||
{
|
{
|
||||||
'name': "Web timeline",
|
'name': "Web timeline",
|
||||||
'summary': """
|
'summary': """
|
||||||
Interactive visualization chart to visualize events in time
|
Interactive visualization chart to visualize events in time
|
||||||
""",
|
""",
|
||||||
"version": "0.1",
|
"version": "8.0.1.0.0",
|
||||||
"author": "ACSONE SA/NV",
|
'author': 'ACSONE SA/NV,'
|
||||||
"category": "Acsone",
|
'Odoo Community Association (OCA)',
|
||||||
|
"category": "Tools",
|
||||||
"website": "http://acsone.eu",
|
"website": "http://acsone.eu",
|
||||||
'depends': ['web', 'project'],
|
'depends': [
|
||||||
'qweb': ['static/src/xml/web_timeline.xml'],
|
'web'
|
||||||
|
],
|
||||||
|
'qweb': [
|
||||||
|
'static/src/xml/web_timeline.xml',
|
||||||
|
],
|
||||||
'data': [
|
'data': [
|
||||||
'views/web_timeline.xml',
|
'views/web_timeline.xml',
|
||||||
'project_view.xml',
|
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# Copyright 2015 ACSONE SA/NV
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
from openerp import models
|
|
||||||
from openerp import api
|
|
||||||
|
|
||||||
|
|
||||||
TIMELINE_VIEW = ('timeline', 'Timeline')
|
|
||||||
|
|
||||||
|
|
||||||
class IrUIView(models.Model):
|
|
||||||
_inherit = 'ir.ui.view'
|
|
||||||
|
|
||||||
@api.model
|
|
||||||
def _setup_fields(self):
|
|
||||||
"""Hack due since the field 'type' is not defined with the new api.
|
|
||||||
"""
|
|
||||||
cls = type(self)
|
|
||||||
type_selection = cls._fields['type'].selection
|
|
||||||
if TIMELINE_VIEW not in type_selection:
|
|
||||||
tmp = list(type_selection)
|
|
||||||
tmp.append(TIMELINE_VIEW)
|
|
||||||
cls._fields['type'].selection = tuple(set(tmp))
|
|
||||||
super(IrUIView, self)._setup_fields()
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# © 2016 ACSONE SA/NV (<http://acsone.eu>)
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
|
|
||||||
|
from . import ir_view
|
|
@ -0,0 +1,25 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2016 ACSONE SA/NV (<http://acsone.eu>)
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
|
|
||||||
|
from openerp import models
|
||||||
|
from openerp import api
|
||||||
|
|
||||||
|
|
||||||
|
TIMELINE_VIEW = ('timeline', 'Timeline')
|
||||||
|
|
||||||
|
|
||||||
|
class IrUIView(models.Model):
|
||||||
|
_inherit = 'ir.ui.view'
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def _setup_fields(self):
|
||||||
|
"""Hack due since the field 'type' is not defined with the new api.
|
||||||
|
"""
|
||||||
|
cls = type(self)
|
||||||
|
type_selection = cls._fields['type'].selection
|
||||||
|
if TIMELINE_VIEW not in type_selection:
|
||||||
|
tmp = list(type_selection)
|
||||||
|
tmp.append(TIMELINE_VIEW)
|
||||||
|
cls._fields['type'].selection = tuple(set(tmp))
|
||||||
|
super(IrUIView, self)._setup_fields()
|
|
@ -1,24 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<openerp>
|
|
||||||
<data>
|
|
||||||
|
|
||||||
<record id="view_task_timeline" model="ir.ui.view">
|
|
||||||
<field name="name">project.task.timeline</field>
|
|
||||||
<field name="model">project.task</field>
|
|
||||||
<field name="type">timeline</field>
|
|
||||||
<field eval="2" name="priority"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<timeline date_start="date_start"
|
|
||||||
date_stop="date_end"
|
|
||||||
date_delay='1'
|
|
||||||
string="Tasks"
|
|
||||||
default_group_by="user_id" event_open_popup="true" colors="#ec7063:user_id == false;#2ecb71:kanban_state=='done';">
|
|
||||||
</timeline>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="project.action_view_task" model="ir.actions.act_window">
|
|
||||||
<field name="view_mode">kanban,tree,form,calendar,gantt,timeline,graph</field>
|
|
||||||
</record>
|
|
||||||
</data>
|
|
||||||
</openerp>
|
|
|
@ -247,7 +247,6 @@ openerp.web_timeline = function(instance) {
|
||||||
var self = this;
|
var self = this;
|
||||||
self.last_domains = domains;
|
self.last_domains = domains;
|
||||||
self.last_contexts = contexts;
|
self.last_contexts = contexts;
|
||||||
// self.reload_gantt();
|
|
||||||
// select the group by
|
// select the group by
|
||||||
var n_group_bys = [];
|
var n_group_bys = [];
|
||||||
if (this.fields_view.arch.attrs.default_group_by) {
|
if (this.fields_view.arch.attrs.default_group_by) {
|
||||||
|
@ -263,14 +262,7 @@ openerp.web_timeline = function(instance) {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
fields = _.uniq(fields.concat(_.pluck(this.colors, "field").concat(n_group_bys)));
|
fields = _.uniq(fields.concat(_.pluck(this.colors, "field").concat(n_group_bys)));
|
||||||
var group_by = self.fields[_.first(n_group_bys)]
|
return $.when(this.has_been_loaded).then(function() {
|
||||||
var read_groups = new instance.web.DataSet(this, group_by.relation, group_by.context)
|
|
||||||
.name_search('', group_by.domain)
|
|
||||||
.then(function(groups){
|
|
||||||
self.groups = groups;
|
|
||||||
});
|
|
||||||
|
|
||||||
return $.when(this.has_been_loaded, read_groups).then(function() {
|
|
||||||
return self.dataset.read_slice(fields, {
|
return self.dataset.read_slice(fields, {
|
||||||
domain: domains,
|
domain: domains,
|
||||||
context: contexts
|
context: contexts
|
||||||
|
@ -304,18 +296,33 @@ openerp.web_timeline = function(instance) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var data = [];
|
var data = [];
|
||||||
var groups = [];
|
var groups = [];
|
||||||
groups.push({id:-1, content: _t('Undefined')})
|
|
||||||
_.each(tasks, function(event) {
|
_.each(tasks, function(event) {
|
||||||
data.push(self.event_data_transform(event));
|
if (event[self.date_start]){
|
||||||
});
|
data.push(self.event_data_transform(event));
|
||||||
_.each(self.groups, function(group){
|
}
|
||||||
groups.push({id: group[0], content: group[1]});
|
|
||||||
});
|
});
|
||||||
|
// get the groups
|
||||||
|
var split_groups = function(tasks, group_bys) {
|
||||||
|
if (group_bys.length === 0)
|
||||||
|
return tasks;
|
||||||
|
var groups = [];
|
||||||
|
groups.push({id:-1, content: _t('-')})
|
||||||
|
_.each(tasks, function(task) {
|
||||||
|
var group_name = task[_.first(group_bys)];
|
||||||
|
if (group_name) {
|
||||||
|
var group = _.find(groups, function(group) { return _.isEqual(group.id, group_name[0]); });
|
||||||
|
if (group === undefined) {
|
||||||
|
group = {id: group_name[0], content: group_name[1]};
|
||||||
|
groups.push(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
|
var groups = split_groups(tasks, group_bys);
|
||||||
this.timeline.setGroups(groups);
|
this.timeline.setGroups(groups);
|
||||||
this.timeline.setItems(data);
|
this.timeline.setItems(data);
|
||||||
this.timeline.setWindow(this.current_window);
|
this.timeline.setWindow(this.current_window);
|
||||||
//this.timeline.moveTo(new Date(), true);
|
|
||||||
//this.timeline.zoom(0.5, new Date());
|
|
||||||
},
|
},
|
||||||
|
|
||||||
do_show: function() {
|
do_show: function() {
|
||||||
|
@ -394,7 +401,6 @@ openerp.web_timeline = function(instance) {
|
||||||
null,
|
null,
|
||||||
{readonly: true, title: title}
|
{readonly: true, title: title}
|
||||||
);
|
);
|
||||||
//pop.on('closed', self, self.reload);
|
|
||||||
var form_controller = pop.view_form;
|
var form_controller = pop.view_form;
|
||||||
form_controller.on("load_record", self, function() {
|
form_controller.on("load_record", self, function() {
|
||||||
var footer = pop.$el.closest(".modal").find(".modal-footer");
|
var footer = pop.$el.closest(".modal").find(".modal-footer");
|
||||||
|
|
Loading…
Reference in New Issue