[MERGE] Merge Kanban view
bzr revid: fme@openerp.com-20110906130201-usfd4sm2ltizhdfc
This commit is contained in:
commit
5aebed0ecc
|
@ -289,7 +289,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
|
|||
});
|
||||
}
|
||||
if (result.domain) {
|
||||
// TODO:
|
||||
// TODO:
|
||||
}
|
||||
this.ready = true;
|
||||
},
|
||||
|
@ -1862,7 +1862,6 @@ openerp.web.form.One2ManyDataSet = openerp.web.BufferedDataSet.extend({
|
|||
});
|
||||
|
||||
openerp.web.form.One2ManyFormView = openerp.web.FormView.extend({
|
||||
|
||||
});
|
||||
|
||||
openerp.web.form.One2ManyListView = openerp.web.ListView.extend({
|
||||
|
|
|
@ -247,7 +247,7 @@ openerp.web.ViewManager = openerp.web.Widget.extend({
|
|||
},
|
||||
/**
|
||||
* Event launched when a controller has been inited.
|
||||
*
|
||||
*
|
||||
* @param {String} view_type type of view
|
||||
* @param {String} view the inited controller
|
||||
*/
|
||||
|
@ -324,7 +324,7 @@ openerp.web.ViewManagerAction = openerp.web.ViewManager.extend({
|
|||
|
||||
var searchview_loaded = this.setup_search_view(
|
||||
searchview_id || false, search_defaults);
|
||||
|
||||
|
||||
// schedule auto_search
|
||||
if (searchview_loaded != null && this.action['auto_search']) {
|
||||
$.when(searchview_loaded, inital_view_loaded)
|
||||
|
@ -668,7 +668,7 @@ openerp.web.View = openerp.web.Widget.extend({
|
|||
return this.rpc('/web/action/load', { action_id: parseInt(action_data.name, 10), context: context }, handler);
|
||||
} else {
|
||||
return dataset.exec_workflow(record_id, action_data.name, handler);
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Directly set a view to use instead of calling fields_view_get. This method must
|
||||
|
@ -752,7 +752,11 @@ openerp.web.views = new openerp.web.Registry();
|
|||
openerp.web.json_node_to_xml = function(node, single_quote, indent) {
|
||||
// For debugging purpose, this function will convert a json node back to xml
|
||||
// Maybe usefull for xml view editor
|
||||
if (typeof(node.tag) !== 'string' || !node.children instanceof Array || !node.attrs instanceof Object) {
|
||||
|
||||
if (typeof(node) === 'string') {
|
||||
return node;
|
||||
}
|
||||
else if (typeof(node.tag) !== 'string' || !node.children instanceof Array || !node.attrs instanceof Object) {
|
||||
throw("Node a json node");
|
||||
}
|
||||
indent = indent || 0;
|
||||
|
@ -770,7 +774,7 @@ openerp.web.json_node_to_xml = function(node, single_quote, indent) {
|
|||
}
|
||||
r += ' ' + attr + '="' + vattr + '"';
|
||||
}
|
||||
if (node.children.length) {
|
||||
if (node.children && node.children.length) {
|
||||
r += '>\n';
|
||||
var childs = [];
|
||||
for (var i = 0, ii = node.children.length; i < ii; i++) {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
import controllers
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"name" : "Base Kanban",
|
||||
"version" : "2.0",
|
||||
"depends" : ["web"],
|
||||
"js": [
|
||||
"static/src/js/kanban.js"
|
||||
],
|
||||
"css": [
|
||||
"static/src/css/kanban.css"
|
||||
],
|
||||
'active': True
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
import main
|
|
@ -0,0 +1,11 @@
|
|||
import web.common as openerpweb
|
||||
|
||||
from web.controllers.main import View
|
||||
|
||||
class KanbanView(View):
|
||||
_cp_path = "/web_kanban/kanbanview"
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def load(self, req, model, view_id):
|
||||
fields_view = self.fields_view_get(req, model, view_id, 'kanban')
|
||||
return {'fields_view': fields_view}
|
|
@ -0,0 +1,102 @@
|
|||
.openerp .oe_kanban_view .oe_column {
|
||||
float: left;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.openerp .oe_kanban_view .ui-sortable-placeholder {
|
||||
border: 1px dotted black;
|
||||
visibility: visible !important;
|
||||
height: 60px !important;
|
||||
}
|
||||
|
||||
.openerp .oe_kanban_view .oe_column_heading {
|
||||
color: #000000;
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.openerp .oe_kanban_action_button {
|
||||
height: 22px;
|
||||
margin: 0;
|
||||
}
|
||||
.openerp .oe_kanban_action_a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.openerp .oe_kanban_box {
|
||||
background: #FFF;
|
||||
border: 2px solid #CCC;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
.openerp .oe_kanban_box_header {
|
||||
background: #EEE;
|
||||
border-bottom: 1px solid #CCC;
|
||||
padding: 2px;
|
||||
height: 2em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.openerp .oe_kanban_box_header h4 {
|
||||
font-size: 130%;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.openerp .oe_kanban_box_header h5 {
|
||||
font-size: 120%;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding: 2px;
|
||||
}
|
||||
.openerp .oe_kanban_box_header h6 {
|
||||
font-size: 110%;
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
padding: 2px;
|
||||
}
|
||||
.openerp .oe_kanban_small {
|
||||
font-size: 80%;
|
||||
}
|
||||
.openerp .oe_kanban_box_content {
|
||||
padding: 4px;
|
||||
}
|
||||
.openerp .oe_kanban_buttons_set {
|
||||
border-top: 1px dotted #CCC;
|
||||
}
|
||||
.openerp .oe_kanban_buttons_set .oe_kanban_left a {
|
||||
border-right: 1px dotted #CCC;
|
||||
padding: 2px;
|
||||
}
|
||||
.openerp .oe_kanban_buttons_set .oe_kanban_right a {
|
||||
border-left: 1px dotted #CCC;
|
||||
padding: 2px;
|
||||
}
|
||||
.openerp .oe_kanban_left {
|
||||
float: left;
|
||||
}
|
||||
.openerp .oe_kanban_right {
|
||||
float: right;
|
||||
}
|
||||
.openerp .oe_kanban_clear {
|
||||
clear: both;
|
||||
}
|
||||
.openerp .oe_kanban_box_show_onclick {
|
||||
display: none;
|
||||
}
|
||||
.openerp .oe_kanban_draghandle {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
/* Custom colors */
|
||||
.openerp .oe_kanban_color_1 .oe_kanban_color_bglight,
|
||||
.openerp .oe_kanban_color_1.oe_kanban_color_bglight {
|
||||
background: #F5F7C4;
|
||||
}
|
||||
.openerp .oe_kanban_color_1 .oe_kanban_color_bgdark,
|
||||
.openerp .oe_kanban_color_1.oe_kanban_color_bgdark {
|
||||
background: #EEF093;
|
||||
}
|
||||
.openerp .oe_kanban_color_1 .oe_kanban_color_border,
|
||||
.openerp .oe_kanban_color_1.oe_kanban_color_border {
|
||||
border-color: #DFE32D;
|
||||
}
|
||||
|
|
@ -0,0 +1,398 @@
|
|||
openerp.web_kanban = function (openerp) {
|
||||
|
||||
QWeb.add_template('/web_kanban/static/src/xml/web_kanban.xml');
|
||||
openerp.web.views.add('kanban', 'openerp.web_kanban.KanbanView');
|
||||
openerp.web_kanban.KanbanView = openerp.web.View.extend({
|
||||
init: function (parent, element_id, dataset, view_id, options) {
|
||||
this._super(parent, element_id);
|
||||
this.set_default_options(options);
|
||||
this.dataset = dataset;
|
||||
this.model = dataset.model;
|
||||
this.domain = dataset.domain;
|
||||
this.context = dataset.context;
|
||||
this.view_id = view_id;
|
||||
this.fields_view = {};
|
||||
this.group_by = [];
|
||||
this.source_index = {};
|
||||
this.all_display_data = false;
|
||||
this.groups = [];
|
||||
this.qweb = new QWeb2.Engine();
|
||||
},
|
||||
start: function() {
|
||||
return this.rpc("/web_kanban/kanbanview/load",
|
||||
{"model": this.model, "view_id": this.view_id}, this.on_loaded);
|
||||
},
|
||||
on_loaded: function(data) {
|
||||
var self = this;
|
||||
this.fields_view = data.fields_view;
|
||||
this.add_qweb_template();
|
||||
if (this.qweb.has_template('kanban-box')) {
|
||||
self.dataset.read_slice(_.keys(self.fields_view.fields), {
|
||||
context: self.dataset.get_context(),
|
||||
domain: self.dataset.get_domain()
|
||||
}, function (records) {
|
||||
self.all_display_data = [{'records': records, 'value': false, 'header': false, 'ids': self.dataset.ids}];
|
||||
self.on_show_data(self.all_display_data);
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
add_qweb_template: function() {
|
||||
for (var i=0, ii=this.fields_view.arch.children.length; i < ii; i++) {
|
||||
var child = this.fields_view.arch.children[i];
|
||||
if (child.tag === "templates") {
|
||||
this.transform_qweb_template(child);
|
||||
this.qweb.add_template(openerp.web.json_node_to_xml(child, true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
do_get_kanban_color: function(variable) {
|
||||
return 'oe_kanban_color_1';
|
||||
},
|
||||
transform_qweb_template: function(node) {
|
||||
switch (node.tag) {
|
||||
case 'field':
|
||||
node.tag = 't';
|
||||
node.attrs['t-esc'] = node.attrs['name'] + '.value';
|
||||
break
|
||||
case 'button':
|
||||
case 'a':
|
||||
var type = node.attrs.type || '';
|
||||
if (_.indexOf('action,object,edit,delete,'.split(','), type) !== -1) {
|
||||
_.each(node.attrs, function(v, k) {
|
||||
node.attrs['data-' + k] = v;
|
||||
delete(node.attrs[k]);
|
||||
});
|
||||
if (node.attrs['data-states']) {
|
||||
var states = _.map(node.attrs['data-states'].split(','), function(state) {
|
||||
return "state.value == '" + _.trim(state) + "'";
|
||||
});
|
||||
node.attrs['t-if'] = states.join(' or ');
|
||||
}
|
||||
if (node.attrs['data-string']) {
|
||||
node.attrs.title = node.attrs['data-string'];
|
||||
}
|
||||
if (node.attrs['data-icon']) {
|
||||
node.children = [{
|
||||
tag: 'img',
|
||||
attrs: {
|
||||
src: '/web/static/src/img/icons/' + node.attrs['data-icon'] + '.png',
|
||||
width: '16',
|
||||
height: '16'
|
||||
}
|
||||
}];
|
||||
}
|
||||
if (node.tag == 'a') {
|
||||
node.attrs.href = '#';
|
||||
} else {
|
||||
node.attrs.type = 'button';
|
||||
}
|
||||
node.attrs['class'] = (node.attrs['class'] || '') + ' oe_kanban_action oe_kanban_action_' + node.tag;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (node.children) {
|
||||
for (var i = 0, ii = node.children.length; i < ii; i++) {
|
||||
this.transform_qweb_template(node.children[i]);
|
||||
}
|
||||
}
|
||||
},
|
||||
on_show_data: function(data) {
|
||||
var self = this;
|
||||
this.$element.html(QWeb.render("KanbanView", {"data": data}));
|
||||
this.on_reload_kanban();
|
||||
var drag_handel = false;
|
||||
if (this.$element.find(".oe_kanban_draghandle").length > 0) {
|
||||
drag_handel = ".oe_kanban_draghandle";
|
||||
}
|
||||
this.$element.find(".oe_column").sortable({
|
||||
connectWith: ".oe_column",
|
||||
handle : drag_handel,
|
||||
start: function(event, ui) {
|
||||
self.source_index['index'] = ui.item.index();
|
||||
self.source_index['column'] = ui.item.parent().attr('id');
|
||||
},
|
||||
stop: self.on_receive_record,
|
||||
});
|
||||
this.$element.find(".oe_column").disableSelection()
|
||||
this.$element.find('button.oe_kanban_button_new').click(this.do_add_record);
|
||||
},
|
||||
on_button_click: function (button_attrs, record_id) {
|
||||
var self = this;
|
||||
if (this.groups.length) {
|
||||
_.each(this.groups, function (group) {
|
||||
group.list([],
|
||||
function (groups) {},
|
||||
function (dataset) {
|
||||
dataset.read_slice([], {}, function(records) {
|
||||
var index = parseInt(_.indexOf(dataset.ids, record_id));
|
||||
if(index >= 0) {
|
||||
self.on_confirm_click(dataset, button_attrs, index, record_id);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
} else {
|
||||
var index = parseInt(_.indexOf(self.dataset.ids, record_id));
|
||||
if (index >= 0) {
|
||||
_.extend(self.dataset, {domain: self.domain, context: self.context});
|
||||
self.on_confirm_click(self.dataset, button_attrs, index, record_id);
|
||||
}
|
||||
}
|
||||
},
|
||||
on_confirm_click: function (dataset, button_attrs, index, record_id) {
|
||||
if (button_attrs.type == 'edit') {
|
||||
this.do_edit_record(dataset, index);
|
||||
} else {
|
||||
this.on_execute_button_click(dataset, button_attrs, record_id);
|
||||
}
|
||||
},
|
||||
do_add_record: function () {
|
||||
this.do_edit_record(this.dataset, null);
|
||||
},
|
||||
do_edit_record: function (dataset, index) {
|
||||
var self = this;
|
||||
_.extend(this.dataset, {
|
||||
domain: dataset.domain,
|
||||
context: dataset.get_context()
|
||||
}).read_slice([], {}, function () {
|
||||
self.dataset.index = index;
|
||||
self.do_switch_view('form');
|
||||
});
|
||||
},
|
||||
do_delete: function (id) {
|
||||
var self = this;
|
||||
return $.when(this.dataset.unlink([id])).then(function () {
|
||||
self.drop_records(id);
|
||||
});
|
||||
},
|
||||
drop_records: function (id) {
|
||||
var self = this;
|
||||
_.each(self.all_display_data, function(data, index) {
|
||||
_.each(data.records, function(record, index_row) {
|
||||
if (parseInt(record.id) == id) {
|
||||
self.all_display_data[index]['records'].splice(index_row, 1);
|
||||
self.all_display_data[index]['ids'].splice(index_row, 1);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
self.$element.find("#main_" + id).remove();
|
||||
},
|
||||
on_execute_button_click: function (dataset, button_attrs, record_id) {
|
||||
var self = this;
|
||||
this.execute_action(
|
||||
button_attrs, dataset,
|
||||
record_id, function () {
|
||||
var count = 1;
|
||||
_.each(self.all_display_data, function(data, index) {
|
||||
self.dataset.read_ids( data.ids, [], function(records){
|
||||
self.all_display_data[index].records = records;
|
||||
if(self.all_display_data.length == count) {
|
||||
self.do_actual_search();
|
||||
}
|
||||
count++;
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
on_receive_record: function (event, ui) {
|
||||
var self = this;
|
||||
var from = ui.item.index();
|
||||
var search_action = false;
|
||||
var to = ui.item.prev().index() || 0;
|
||||
if (!ui.item.attr("id")) {
|
||||
return false;
|
||||
}
|
||||
// TODO fme: check what was this sequence
|
||||
if (self.fields_view.fields.sequence && (self.source_index.index >= 0 && self.source_index.index != from) ||
|
||||
(self.source_index.column && self.source_index.column != ui.item.parent().attr('id'))) {
|
||||
var child_record = ui.item.parent().children();
|
||||
var data, sequence = 1, index = to;
|
||||
child_record.splice(0, to);
|
||||
var flag = false;
|
||||
if (to >= 0 && child_record) {
|
||||
var record_id = parseInt($(child_record).attr("id").split("_")[1]);
|
||||
if (record_id) {
|
||||
_.each(self.all_display_data, function(data, index) {
|
||||
_.each(data.records, function(record, index_row) {
|
||||
if(record_id == record.id && record.sequence) {
|
||||
sequence = record.sequence;
|
||||
flag = true;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if(flag) {return false;}
|
||||
});
|
||||
}
|
||||
}
|
||||
_.each(child_record, function (child) {
|
||||
var child_id = parseInt($(child).attr("id").split("_")[1]);
|
||||
if (child_id) {
|
||||
flag = false;
|
||||
_.each(self.all_display_data, function(data, index) {
|
||||
_.each(data.records, function(record, index_row) {
|
||||
if(parseInt(record.id) == child_id) {
|
||||
self.all_display_data[index]['records'][index_row]['sequence'] = sequence;
|
||||
flag = true;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if (flag) {return false;}
|
||||
});
|
||||
self.dataset.write(child_id, {sequence: sequence});
|
||||
sequence++;
|
||||
search_action = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (self.group_by.length > 0 && self.source_index.column && self.source_index.column != ui.item.parent().attr('id')) {
|
||||
var value = ui.item.closest("td").attr("id");
|
||||
if (value) {
|
||||
var data_val = {};
|
||||
var wirte_id = parseInt(ui.item.attr("id").split("_")[1]);
|
||||
value = value.split("_")[1];
|
||||
if (value == 'false') {
|
||||
value = false;
|
||||
}
|
||||
var update_record = false;
|
||||
_.each(self.all_display_data, function(data, index) {
|
||||
_.each(data.records, function(record, index_row) {
|
||||
if(parseInt(record.id) == wirte_id) {
|
||||
self.all_display_data[index]['records'][index_row][self.group_by[0]] = value;
|
||||
update_record = self.all_display_data[index]['records'].splice(index_row,1)
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if (update_record) {return false;}
|
||||
});
|
||||
_.each(self.all_display_data, function(data, index) {
|
||||
if (data.value == value || (data.value == 'false' && value == false)) {
|
||||
self.all_display_data[index]['records'].push(update_record[0]);
|
||||
}
|
||||
});
|
||||
data_val[self.group_by[0]] = value;
|
||||
self.dataset.write(wirte_id, data_val);
|
||||
search_action = true;
|
||||
}
|
||||
}
|
||||
if (search_action) {
|
||||
self.on_reload_kanban();
|
||||
}
|
||||
this.source_index = {};
|
||||
},
|
||||
on_reload_kanban: function (){
|
||||
var self = this;
|
||||
_.each(self.all_display_data, function(data, index) {
|
||||
if (data.records.length > 0){
|
||||
_.each(data.records, function(record) {
|
||||
self.$element.find("#main_" + record.id).children().remove();
|
||||
self.$element.find("#main_" + record.id).append(self.qweb.render('kanban-box', self.do_transform_record(record)));
|
||||
});
|
||||
} else {
|
||||
self.$element.find("#column_" + data.value).remove();
|
||||
self.all_display_data.splice(index, 1);
|
||||
}
|
||||
});
|
||||
this.$element.find('.oe_kanban_action').click(function() {
|
||||
var record_id = $(this).closest(".oe_kanban_record").attr("id");
|
||||
if (record_id) {
|
||||
record_id = parseInt(record_id.split("_")[1])
|
||||
if (record_id) {
|
||||
if ($(this).data("type") == "delete") {
|
||||
self.do_delete(record_id);
|
||||
} else {
|
||||
var button_attrs = $(this).data()
|
||||
self.on_button_click(button_attrs, record_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
this.$element.find('.oe_kanban_record').click(function() {
|
||||
$(this).find('.oe_kanban_box_show_onclick').removeClass('oe_kanban_box_show_onclick');
|
||||
});
|
||||
},
|
||||
do_transform_record: function(record) {
|
||||
var self = this,
|
||||
new_record = {};
|
||||
_.each(record, function(value, name) {
|
||||
var r = _.clone(self.fields_view.fields[name]);
|
||||
r.raw_value = value;
|
||||
r.value = openerp.web.format_value(value, r);
|
||||
new_record[name] = r;
|
||||
});
|
||||
new_record.__kanban_color = this.do_get_kanban_color;
|
||||
return new_record;
|
||||
},
|
||||
do_search: function (domains, contexts, group_by) {
|
||||
var self = this;
|
||||
this.rpc('/web/session/eval_domain_and_context', {
|
||||
domains: domains,
|
||||
contexts: contexts,
|
||||
group_by_seq: group_by
|
||||
}, function (results) {
|
||||
self.domain = results.domain;
|
||||
self.context = results.context;
|
||||
self.group_by = results.group_by;
|
||||
self.do_actual_search();
|
||||
});
|
||||
},
|
||||
do_actual_search : function () {
|
||||
var self = this;
|
||||
self.datagroup = new openerp.web.DataGroup(self, self.model, self.domain, self.context, self.group_by || []);
|
||||
self.dataset.context = self.context;
|
||||
self.dataset.domain = self.domain;
|
||||
self.datagroup.list([],
|
||||
function (groups) {
|
||||
self.groups = groups;
|
||||
self.do_render_group(groups);
|
||||
},
|
||||
function (dataset) {
|
||||
self.domain = dataset.domain;
|
||||
self.context = dataset.context;
|
||||
self.groups = [];
|
||||
self.dataset.read_slice([], {}, function(records) {
|
||||
self.all_display_data = [{'records': records, 'value':false, 'header' : false, 'ids': self.dataset.ids}];
|
||||
self.$element.find(".oe_kanban_view").remove();
|
||||
self.on_show_data(self.all_display_data);
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
do_render_group : function (datagroups) {
|
||||
this.all_display_data = [];
|
||||
var self = this;
|
||||
_.each(datagroups, function (group) {
|
||||
self.dataset.context = group.context;
|
||||
self.dataset.domain = group.domain;
|
||||
var group_name = group.value;
|
||||
var group_value = group.value;
|
||||
if (!group.value) {
|
||||
group_name = "Undefined";
|
||||
group_value = 'false';
|
||||
} else if (group.value instanceof Array) {
|
||||
group_name = group.value[1];
|
||||
group_value = group.value[0];
|
||||
}
|
||||
self.dataset.read_slice([], {}, function(records) {
|
||||
self.all_display_data.push({"value" : group_value, "records": records, 'header':group_name, 'ids': self.dataset.ids});
|
||||
if (datagroups.length == self.all_display_data.length) {
|
||||
self.$element.find(".oe_kanban_view").remove();
|
||||
self.on_show_data(self.all_display_data);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
do_show: function () {
|
||||
this.$element.show();
|
||||
},
|
||||
do_hide: function () {
|
||||
this.$element.hide();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
|
|
@ -0,0 +1,25 @@
|
|||
<template>
|
||||
<t t-name="KanbanView">
|
||||
<table style="width:100%;" class="oe_kanban_view">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="oe_form_header">
|
||||
<button type="button" class="oe_kanban_button_new">New</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td t-foreach="data" t-as="columns" class="oe_table_column oe_column_heading" t-att-id="'column_' + columns.value">
|
||||
<t t-if="columns.value" t-esc="columns.header"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td t-foreach="data" t-as="columns" class="oe_table_column" t-att-id="'column_' + columns.value" t-attf-style="width: #{Math.round(99 / data.length)}%">
|
||||
<div class="oe_column" t-att-id="'column_' + columns.value">
|
||||
<div t-foreach="columns.records" t-as="record" class="oe_kanban_record" t-att-id="'main_' + record.id"/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</t>
|
||||
</template>
|
Loading…
Reference in New Issue