From 4c53003dfe1c5cfb09c247eb1ec9a0bafe42bf90 Mon Sep 17 00:00:00 2001 From: chintanambaliya-flectra Date: Fri, 1 Dec 2017 14:22:43 +0530 Subject: [PATCH] [IMP] Enable events like Draggable and Resizable --- .../web/static/lib/jquery.ganttView/date.js | 2 +- .../lib/jquery.ganttView/jquery.ganttView.css | 126 +++++------ .../lib/jquery.ganttView/jquery.ganttView.js | 6 +- .../src/js/views/gantt/gantt_controller.js | 29 ++- .../static/src/js/views/gantt/gantt_model.js | 214 ++++++++---------- .../src/js/views/gantt/gantt_renderer.js | 122 ++++++++++ .../static/src/js/views/gantt/gantt_view.js | 6 +- addons/web/static/src/xml/base.xml | 29 +++ addons/web/views/webclient_templates.xml | 5 +- 9 files changed, 319 insertions(+), 220 deletions(-) create mode 100644 addons/web/static/src/js/views/gantt/gantt_renderer.js diff --git a/addons/web/static/lib/jquery.ganttView/date.js b/addons/web/static/lib/jquery.ganttView/date.js index 3cb003fa..2ef3a1c5 100644 --- a/addons/web/static/lib/jquery.ganttView/date.js +++ b/addons/web/static/lib/jquery.ganttView/date.js @@ -3,7 +3,7 @@ * @author: Coolite Inc. http://www.coolite.com/ * @date: 2008-05-13 * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved. - * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/. + * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/. * @website: http://www.datejs.com/ */ Date.CultureInfo={name:"en-US",englishName:"English (United States)",nativeName:"English (United States)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"mdy",formatPatterns:{shortDate:"M/d/yyyy",longDate:"dddd, MMMM dd, yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, MMMM dd, yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\+|aft(er)?|from|hence)/i,subtract:/^(\-|bef(ore)?|ago)/i,yesterday:/^yes(terday)?/i,today:/^t(od(ay)?)?/i,tomorrow:/^tom(orrow)?/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^mn|min(ute)?s?/i,hour:/^h(our)?s?/i,week:/^w(eek)?s?/i,month:/^m(onth)?s?/i,day:/^d(ay)?s?/i,year:/^y(ear)?s?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\.?m?\.?|p\.?m?\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,ordinalSuffix:/^\s*(st|nd|rd|th)/i,timeContext:/^\s*(\:|a(?!u|p)|p)/i},timezones:[{name:"UTC",offset:"-000"},{name:"GMT",offset:"-000"},{name:"EST",offset:"-0500"},{name:"EDT",offset:"-0400"},{name:"CST",offset:"-0600"},{name:"CDT",offset:"-0500"},{name:"MST",offset:"-0700"},{name:"MDT",offset:"-0600"},{name:"PST",offset:"-0800"},{name:"PDT",offset:"-0700"}]}; diff --git a/addons/web/static/lib/jquery.ganttView/jquery.ganttView.css b/addons/web/static/lib/jquery.ganttView/jquery.ganttView.css index 6cb1b578..09a284a9 100644 --- a/addons/web/static/lib/jquery.ganttView/jquery.ganttView.css +++ b/addons/web/static/lib/jquery.ganttView/jquery.ganttView.css @@ -11,145 +11,127 @@ div.ganttview-vtheader-item-name, div.ganttview-vtheader-series, div.ganttview-grid, div.ganttview-grid-row-cell { - float: left; + float: left; } div.ganttview-hzheader-month, div.ganttview-hzheader-day { - text-align: center; + text-align: center; } div.ganttview-grid-row-cell.last, div.ganttview-hzheader-day.last, div.ganttview-hzheader-month.last { - border-right: none; + border-right: none; } div.ganttview { - border: 1px solid #999; + border: 1px solid #999; } - /* Horizontal Header */ div.ganttview-hzheader-month { - width: 60px; - height: 20px; - border-right: 1px solid #d0d0d0; - line-height: 20px; + width: 60px; + height: 20px; + border-right: 1px solid #d0d0d0; + line-height: 20px; } div.ganttview-hzheader-day { - width: 20px; - height: 20px; - border-right: 1px solid #f0f0f0; - border-top: 1px solid #d0d0d0; - line-height: 20px; - color: #777; + width: 20px; + height: 20px; + border-right: 1px solid #f0f0f0; + border-top: 1px solid #d0d0d0; + line-height: 20px; + color: #777; } - /* Vertical Header */ div.ganttview-vtheader { - margin-top: 41px; - width: auto; - overflow: hidden; - background-color: #fff; + margin-top: 41px; + width: auto; + overflow: hidden; + background-color: #fff; } div.ganttview-vtheader-item { - overflow: hidden; - color: #666; + overflow: hidden; + color: #666; } div.ganttview-vtheader-item-name { - width: 100px; - padding-left: 5px; - border-top: 1px solid #d0d0d0; - line-height: 16px; + width: 100px; + padding-left: 5px; + border-top: 1px solid #d0d0d0; + line-height: 16px; } div.ganttview-vtheader-series-name { - width: 130px; - height: 31px; - border-top: 1px solid #d0d0d0; - line-height: 16px; - padding-left: 5px; + width: 130px; + height: 31px; + border-top: 1px solid #d0d0d0; + line-height: 16px; + padding-left: 5px; } - /* Slider */ div.ganttview-slide-container { - overflow: auto; - border-left: 1px solid #999; + overflow: auto; + border-left: 1px solid #999; } - /* Grid */ div.ganttview-grid-row-cell { - width: 20px; - height: 31px; - border-right: 1px solid #f0f0f0; - border-top: 1px solid #f0f0f0; + width: 20px; + height: 31px; + border-right: 1px solid #f0f0f0; + border-top: 1px solid #f0f0f0; } div.ganttview-grid-row-cell.ganttview-weekend { - background-color: #fafafa; + background-color: #fafafa; } div.ganttview-grid-row-cell.ganttview-today { - background-color: #F7F9FF !important; + background-color: #F7F9FF !important; } /* Blocks */ div.ganttview-blocks { - margin-top: 40px; + margin-top: 40px; } div.ganttview-block-container { - height: 31px; - padding-top: 4px; - text-align: left; + height: 31px; + padding-top: 4px; + text-align: left; } div.ganttview-block { - position: relative; - height: 25px; - background-color: #E5ECF9; - border: 1px solid #c0c0c0; - border-radius: 3px; - -moz-border-radius: 3px; - -webkit-border-radius: 3px; + position: relative; + height: 25px; + background-color: #E5ECF9; + border: 1px solid #c0c0c0; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; } div.ganttview-block-text { - position: absolute; - height: 12px; - font-size: 0.8em; - color: #999; - padding: 2px 3px; + position: absolute; + height: 12px; + font-size: 0.8em; + color: #999; + padding: 2px 3px; } - /* Adjustments for jQuery UI Styling */ div.ganttview-block div.ui-resizable-handle.ui-resizable-s { - bottom: -0; + bottom: -0; } - -/* bootstrap css fix - begin */ -/* Uncomment if bootstrap.js is giving you issues */ -/* https://github.com/thegrubbsian/jquery.ganttView/issues/29 */ -/* -#ganttChart div, -#ganttChart div:before, -#ganttChart div:after { --webkit-box-sizing: initial; --moz-box-sizing: initial; -box-sizing: initial; -} -*/ diff --git a/addons/web/static/lib/jquery.ganttView/jquery.ganttView.js b/addons/web/static/lib/jquery.ganttView/jquery.ganttView.js index 51aa4aa7..1623f11f 100644 --- a/addons/web/static/lib/jquery.ganttView/jquery.ganttView.js +++ b/addons/web/static/lib/jquery.ganttView/jquery.ganttView.js @@ -229,11 +229,11 @@ behavior: { for (var i = 0; i < data.length; i++) { for (var j = 0; j < data[i].series.length; j++) { var series = data[i].series[j]; - var size = DateUtils.daysBetween(series.start, series.end) ? DateUtils.daysBetween(series.start, series.end) : 1; - var offset = DateUtils.daysBetween(start, series.start) == 0 ? DateUtils.daysBetween(start, series.start) : DateUtils.daysBetween(start, series.start) - 1; + var size = DateUtils.daysBetween(series.start, series.end) + 1; + var offset = DateUtils.daysBetween(start, series.start); var block = jQuery("
", { "class": "ganttview-block", - "title": series.name + ", " + size + " days", + "title": series.name + ", " + size + " days \n"+ series.start +" to "+ series.end, "css": { "width": ((size * cellWidth) - 7) + "px", "margin-left": ((offset * cellWidth) + 3) + "px" diff --git a/addons/web/static/src/js/views/gantt/gantt_controller.js b/addons/web/static/src/js/views/gantt/gantt_controller.js index 8089cd1d..2c23fae1 100644 --- a/addons/web/static/src/js/views/gantt/gantt_controller.js +++ b/addons/web/static/src/js/views/gantt/gantt_controller.js @@ -5,24 +5,21 @@ flectra.define('web.GanttController', function (require) { *---------------------------------------------------------*/ var AbstractController = require('web.AbstractController'); -var core = require('web.core'); -var qweb = core.qweb; - -var GanttController = AbstractController.extend({ - template: "GanttView", - /** - * @override - * @param {Widget} parent - * @param {GanttModel} model - * @param {AbstractRenderer} renderer - * @param {Object} params - */ - init: function(parent, model, renderer, params) { - this._super.apply(this, arguments); +return AbstractController.extend({ + custom_events: _.extend({}, AbstractController.prototype.custom_events, { + updateRecord: '_onUpdateRecord', + }), + _onUpdateRecord: function (record) { + this._rpc({ + model: this.model.modelName, + method: 'write', + args: [record.data.id, { + [this.model.data.arch['date_start']]: record.data.start.toString('yyyy-M-d'), + [this.model.data.arch['date_stop']]: record.data.end.toString('yyyy-M-d'), + }], + }).then(this.reload.bind(this)); }, }); -return GanttController; - }); diff --git a/addons/web/static/src/js/views/gantt/gantt_model.js b/addons/web/static/src/js/views/gantt/gantt_model.js index 5b709c75..659ab401 100644 --- a/addons/web/static/src/js/views/gantt/gantt_model.js +++ b/addons/web/static/src/js/views/gantt/gantt_model.js @@ -6,169 +6,139 @@ flectra.define('web.GanttModel', function (require) { * server. It basically just do a search_read and format/normalize data. */ -var core = require('web.core'); var AbstractModel = require('web.AbstractModel'); -var _t = core._t; - return AbstractModel.extend({ /** * @override + * @param {Object} params */ init: function () { this._super.apply(this, arguments); + this.data = null; }, /** * @override - * @param {any} params + * @param {Object} params + * @param {string[]} params.groupedBy a list of valid field names + * @param {Object} params.context + * @param {string[]} params.domain * @returns {Deferred} */ - load: function(params) { - var self = this; + load: function (params) { this.modelName = params.modelName; - this.gantt = { - data: [], + this.data = { + records: [], domain: params.domain, - groupBy: params.groupedBy, context: params.context, + groupedBy: params.groupedBy || [], arch: params.arch.attrs, }; - return this._loadGantt(); + return this._loadData(); }, /** * @override - * @param {any} handle ignored! * @param {Object} params - * @param {string[]} [params.domain] - * @param {string[]} [params.groupBy] + * @param {string[]} params.groupedBy a list of valid field names + * @param {Object} params.context + * @param {string[]} params.domain * @returns {Deferred} */ - reload: function(handle, params) { + reload: function (handle, params) { if (params.domain) { - this.gantt.domain = params.domain; + this.data.domain = params.domain; + } + if (params.context) { + this.data.context = params.context; } if (params.groupBy) { - this.gantt.groupBy = params.groupBy; + this.data.groupedBy = params.groupBy; } - return this._loadGantt(); + return this._loadData(); }, /** - * Fetch and process gantt data. It is basically a read_group with correct - * fields. - * * @returns {Deferred} */ - _loadGantt: function() { + _loadData: function () { var self = this; - this.gantt.data = []; return this._rpc({ model: this.modelName, method: 'search_read', - context: this.gantt.context, - domain: this.gantt.domain, - groupBy: this.gantt.groupBy, - }).then(function(raw_datas) { - /** - * GroupBy is only supported till 1st level ! - * @todo Flectra: Support Multi level GroupBy - */ - if(self.gantt.groupBy.length) { - _.each(raw_datas, function(raw_data) { - var grpByStr = raw_data[self.gantt.groupBy[0]] ? raw_data[self.gantt.groupBy[0]] : 'Undefined'; - if(grpByStr && grpByStr instanceof Array) { - grpByStr = raw_data[self.gantt.groupBy[0]] ? raw_data[self.gantt.groupBy[0]][1] : 'Undefined'; - } - var keyCheck = _.findKey(self.gantt.data, {name: grpByStr}); - if(!keyCheck) { - self.gantt.data.push({ - name: grpByStr, - series: [], - }); - } - keyCheck = _.findKey(self.gantt.data, {name: grpByStr}); - if(self.gantt.data[keyCheck]) { - if(raw_data[self.gantt.arch['date_stop']]) { - self.gantt.data[keyCheck].series.push({ - id: raw_data['id'], name: raw_data['display_name'], - start: raw_data[self.gantt.arch['date_start']], end: raw_data[self.gantt.arch['date_stop']] - }); - } else { - self.gantt.data[keyCheck].series.push({ - id: raw_data['id'], name: raw_data['display_name'], - start: raw_data[self.gantt.arch['date_start']], end: raw_data[self.gantt.arch['date_start']] - }); - } - } - }); - } else { - _.each(raw_datas, function(raw_data) { - if(raw_data[self.gantt.arch['date_stop']]) { - self.gantt.data.push({ - series: [ - {id: raw_data['id'], name: raw_data['display_name'], - start: raw_data[self.gantt.arch['date_start']], end: raw_data[self.gantt.arch['date_stop']]}, - ], + context: this.data.context, + domain: this.data.domain, + }) + .then(function (records) { + self.data.records = self._processData(records); + }); + }, + _processData: function (raw_datas) { + /** + * GroupBy is only supported till 1st level ! + * @todo Flectra: Support Multi level GroupBy + */ + var self = this; + var ganttData = []; + if (self.data.groupedBy.length) { + _.each(raw_datas, function (raw_data) { + var grpByStr = raw_data[self.data.groupedBy[0]] ? raw_data[self.data.groupedBy[0]] : 'Undefined'; + if (grpByStr && grpByStr instanceof Array) { + grpByStr = raw_data[self.data.groupedBy[0]] ? raw_data[self.data.groupedBy[0]][1] : 'Undefined'; + } + var keyCheck = _.findKey(ganttData, {name: grpByStr}); + if (!keyCheck) { + ganttData.push({ + name: grpByStr, + series: [], + }); + } + keyCheck = _.findKey(ganttData, {name: grpByStr}); + if (ganttData[keyCheck]) { + if (raw_data[self.data.arch['date_stop']]) { + ganttData[keyCheck].series.push({ + id: raw_data['id'], + name: raw_data['display_name'], + start: raw_data[self.data.arch['date_start']].split(' ')[0], + end: raw_data[self.data.arch['date_stop']].split(' ')[0] }); } else { - self.gantt.data.push({ - series: [ - {id: raw_data['id'], name: raw_data['display_name'], - start: raw_data[self.gantt.arch['date_start']], end: raw_data[self.gantt.arch['date_start']]}, - ], + ganttData[keyCheck].series.push({ + id: raw_data['id'], + name: raw_data['display_name'], + start: raw_data[self.data.arch['date_start']].split(' ')[0], + end: raw_data[self.data.arch['date_start']].split(' ')[0] }); } - }); - } - - /** - * Render the Gantt view. - * - * Note that This method is synchronous, but the actual rendering is done - * asynchronously (in a setTimeout). - * - */ - setTimeout(function() { - $(".o_gantt_view_container").empty(); - $(".o_gantt_view_container").ganttView({ - data: self.gantt.data, - slideWidth: 'auto', - cellWidth: 20, - behavior: { - clickable: false, - draggable: false, - resizable: false, - /** - * @todo Flectra: - * Turn-On below events & related behavior/functions - */ -// onClick: function(data) {}, -// -// onResize: function(data) { -// self.updateRecord(data); -// }, -// -// onDrag: function(data) { -// self.updateRecord(data); -// }, - } - }); - }, 0); - }); + } + }); + } else { + _.each(raw_datas, function (raw_data) { + if (raw_data[self.data.arch['date_stop']]) { + ganttData.push({ + series: [ + { + id: raw_data['id'], + name: raw_data['display_name'], + start: raw_data[self.data.arch['date_start']].split(' ')[0], + end: raw_data[self.data.arch['date_stop']].split(' ')[0] + }, + ], + }); + } else { + ganttData.push({ + series: [ + { + id: raw_data['id'], + name: raw_data['display_name'], + start: raw_data[self.data.arch['date_start']].split(' ')[0], + end: raw_data[self.data.arch['date_start']].split(' ')[0] + }, + ], + }); + } + }); + } + return ganttData; }, - -// updateRecord: function(data) { -// var self = this; -// return this._rpc({ -// model: self.modelName, -// method: 'write', -// args: [[data.id], { -// [self.gantt.arch['date_start']]: data.start, -// [self.gantt.arch['date_stop']]: data.end, -// }], -// context: self.gantt.context, -// }); -// }, - }); }); diff --git a/addons/web/static/src/js/views/gantt/gantt_renderer.js b/addons/web/static/src/js/views/gantt/gantt_renderer.js new file mode 100644 index 00000000..42b481d2 --- /dev/null +++ b/addons/web/static/src/js/views/gantt/gantt_renderer.js @@ -0,0 +1,122 @@ +flectra.define('web.GanttRenderer', function (require) { +"use strict"; + +/** + * The graph renderer turns the data from the graph model into a nice looking + * svg chart. This code uses the nvd3 library. + * + * Note that we use a custom build for the nvd3, with only the model we actually + * use. + */ + +var core = require('web.core'); +var AbstractRenderer = require('web.AbstractRenderer'); +var Dialog = require('web.Dialog'); + +var _t = core._t; +var QWeb = core.qweb; + +return AbstractRenderer.extend({ + template: "GanttView", + /** + * @override + * @param {Widget} parent + * @param {Object} state + * @param {Object} params + * @param {boolean} params.stacked + */ + init: function (parent, state, params) { + this.parent = parent; + this._super.apply(this, arguments); + }, + + /** + * Render the chart. + * + * Note that This method is synchronous, but the actual rendering is done + * asynchronously (in a setTimeout). The reason for that is that nvd3/d3 + * needs to be in the DOM to correctly render itself. So, we trick Flectra by + * returning immediately, then wait a tiny interval before actually + * displaying the data. + * + * @returns {Deferred} The _super deferred is actually resolved immediately + */ + _render: function () { + this.data = this.parent.active_view.controller.model.data; + this._loadGanttView(); + return $.when(); + }, + _loadGanttView: function () { + var self = this; + this.$el.empty().ganttView({ + data: self.data.records, + slideWidth: 'auto', + cellWidth: 20, + behavior: { + onClick: function (data) { + var dialog = new Dialog(self, { + title: _t(data.name), + $content: $(QWeb.render('GanttViewWizard')), + size: 'small', + buttons: [ + {text: _t("Save"), classes: 'btn-success', click: _.bind(_callSave, self)}, + {text: _t("Cancel"), classes: 'btn-danger', close: true} + ] + }).open(); + + dialog.opened().then(function () { + var datepickers_options = { + keepOpen: true, + minDate: moment({y: 1900}), + maxDate: moment().add(200, "y"), + calendarWeeks: true, + icons: { + time: 'fa fa-clock-o', + date: 'fa fa-calendar', + next: 'fa fa-chevron-right', + previous: 'fa fa-chevron-left', + up: 'fa fa-chevron-up', + down: 'fa fa-chevron-down', + }, + locale: moment.locale(), + format: "YYYY-MM-DD", + ignoreReadonly: true + }; + dialog.$el.find('input#start_date').val(data.start); + dialog.$el.find('input#end_date').val(data.end); + dialog.$el.find('input#start_date, input#end_date').datetimepicker(datepickers_options); + }); + + function _callSave(event) { + var newData = { + start: dialog.$el.find('input#start_date').val().toString(), + end: dialog.$el.find('input#end_date').val().toString(), + id: data.id + }; + if (data.start !== newData.start || data.end !== newData.end) { + var start_data = new Date(dialog.$el.find('input#start_date').val().toString()).getTime(); + var end_data = new Date(dialog.$el.find('input#end_date').val().toString()).getTime(); + if(start_data <= end_data){ + self.trigger_up('updateRecord', newData); + dialog.close(); + }else { + self.do_warn(_t("Warning"), _t("Start date should be less than or equal to End date")); + } + } + } + }, + + onResize: function (data) { + self.trigger_up('updateRecord', data); + }, + + onDrag: function (data) { + self.trigger_up('updateRecord', data); + }, + } + }); + this.$el.removeAttr('style'); + }, +}); + +}); diff --git a/addons/web/static/src/js/views/gantt/gantt_view.js b/addons/web/static/src/js/views/gantt/gantt_view.js index f294babd..3d9fe207 100644 --- a/addons/web/static/src/js/views/gantt/gantt_view.js +++ b/addons/web/static/src/js/views/gantt/gantt_view.js @@ -4,10 +4,9 @@ flectra.define('web.GanttView', function (require) { var AbstractView = require('web.AbstractView'); var core = require('web.core'); var GanttModel = require('web.GanttModel'); +var GanttRenderer = require('web.GanttRenderer'); var Controller = require('web.GanttController'); -var AbstractRenderer = require('web.AbstractRenderer'); -var _t = core._t; var _lt = core._lt; var GanttView = AbstractView.extend({ @@ -16,7 +15,7 @@ var GanttView = AbstractView.extend({ config: { Model: GanttModel, Controller: Controller, - Renderer: AbstractRenderer, + Renderer: GanttRenderer, }, /** * @override @@ -24,7 +23,6 @@ var GanttView = AbstractView.extend({ init: function(viewInfo) { this._super.apply(this, arguments); var arch = viewInfo.arch; - var fields = viewInfo.fields; this.loadParams.arch = arch; }, }); diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 5c3b0142..2dce0ab9 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -532,6 +532,35 @@
+ + + + + + + + + + + + +
+ + +
+ +
+
+ + +
+ +
+
+
+
diff --git a/addons/web/views/webclient_templates.xml b/addons/web/views/webclient_templates.xml index a03111fb..93f8e62a 100644 --- a/addons/web/views/webclient_templates.xml +++ b/addons/web/views/webclient_templates.xml @@ -242,9 +242,10 @@