diff --git a/addons/account/__init__.py b/addons/account/__init__.py index 90fbdb83980..bc27e14380c 100644 --- a/addons/account/__init__.py +++ b/addons/account/__init__.py @@ -19,10 +19,10 @@ # ############################################################################## +import partner import account import installer import project -import partner import account_invoice import account_bank_statement import account_bank diff --git a/addons/account/account_bank_view.xml b/addons/account/account_bank_view.xml index 4b3436c8a51..8ceb8a91885 100644 --- a/addons/account/account_bank_view.xml +++ b/addons/account/account_bank_view.xml @@ -9,7 +9,6 @@ Partner Bank Accounts - Journal res.partner.bank - form @@ -26,7 +25,6 @@ Partner Bank Accounts - Add currency on tree res.partner.bank - tree diff --git a/addons/account/account_cash_statement.py b/addons/account/account_cash_statement.py index 2bb89a84cdc..9af0dcf60f4 100644 --- a/addons/account/account_cash_statement.py +++ b/addons/account/account_cash_statement.py @@ -169,7 +169,7 @@ class account_cash_statement(osv.osv): return result _columns = { - 'total_entry_encoding': fields.function(_get_sum_entry_encoding, string="Total Cash Transactions", + 'total_entry_encoding': fields.function(_get_sum_entry_encoding, string="Total Transactions", store = { 'account.bank.statement': (lambda self, cr, uid, ids, context=None: ids, ['line_ids','move_line_ids'], 10), 'account.bank.statement.line': (_get_statement_from_line, ['amount'], 10), diff --git a/addons/account/account_installer.xml b/addons/account/account_installer.xml index d2661674bae..c92d4eda602 100644 --- a/addons/account/account_installer.xml +++ b/addons/account/account_installer.xml @@ -3,7 +3,6 @@ account.installer.form account.installer - form
diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py index 064ba419ebd..012bde42eff 100644 --- a/addons/account/account_invoice.py +++ b/addons/account/account_invoice.py @@ -1351,11 +1351,11 @@ class account_invoice_line(osv.osv): 'uos_id': fields.many2one('product.uom', 'Unit of Measure', ondelete='set null'), 'product_id': fields.many2one('product.product', 'Product', ondelete='set null'), 'account_id': fields.many2one('account.account', 'Account', required=True, domain=[('type','<>','view'), ('type', '<>', 'closed')], help="The income or expense account related to the selected product."), - 'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Account')), + 'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Product Price')), 'price_subtotal': fields.function(_amount_line, string='Subtotal', type="float", digits_compute= dp.get_precision('Account'), store=True), - 'quantity': fields.float('Quantity', required=True), - 'discount': fields.float('Discount (%)', digits_compute= dp.get_precision('Account')), + 'quantity': fields.float('Quantity', digits_compute= dp.get_precision('Product Unit of Measure'), required=True), + 'discount': fields.float('Discount (%)', digits_compute= dp.get_precision('Discount')), 'invoice_line_tax_id': fields.many2many('account.tax', 'account_invoice_line_tax', 'invoice_line_id', 'tax_id', 'Taxes', domain=[('parent_id','=',False)]), 'account_analytic_id': fields.many2one('account.analytic.account', 'Analytic Account'), 'company_id': fields.related('invoice_id','company_id',type='many2one',relation='res.company',string='Company', store=True, readonly=True), diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml index 501a50b96c2..143c5514141 100644 --- a/addons/account/account_invoice_view.xml +++ b/addons/account/account_invoice_view.xml @@ -6,7 +6,6 @@ account.invoice.calendar account.invoice - calendar @@ -18,7 +17,6 @@ account.invoice.graph account.invoice - graph @@ -30,7 +28,6 @@ account.invoice.line.tree account.invoice.line - tree @@ -47,7 +44,6 @@ account.invoice.line.form account.invoice.line - form @@ -78,7 +74,6 @@ account.invoice.tax.tree account.invoice.tax - tree @@ -94,7 +89,6 @@ account.invoice.tax.form account.invoice.tax - form @@ -120,7 +114,6 @@ account.invoice.tree account.invoice - tree @@ -146,10 +139,9 @@ account.invoice.supplier.form account.invoice - form 2 - +

-

@@ -347,7 +343,7 @@ - +
+
@@ -439,7 +436,6 @@ account.invoice.select account.invoice - search diff --git a/addons/account/account_unit_test.xml b/addons/account/account_unit_test.xml index ad4540b9806..7795c2700cc 100644 --- a/addons/account/account_unit_test.xml +++ b/addons/account/account_unit_test.xml @@ -5,7 +5,7 @@ - + draft out_invoice diff --git a/addons/account/account_view.xml b/addons/account/account_view.xml index 24d21cff3e8..5bf45aab487 100644 --- a/addons/account/account_view.xml +++ b/addons/account/account_view.xml @@ -9,9 +9,8 @@ account.fiscalyear.form account.fiscalyear - form -
+
diff --git a/addons/base_action_rule/base_action_rule.py b/addons/base_action_rule/base_action_rule.py index 7699256985c..b6eacda63c0 100644 --- a/addons/base_action_rule/base_action_rule.py +++ b/addons/base_action_rule/base_action_rule.py @@ -292,7 +292,7 @@ the rule to mark CC(mail to any other person defined in actions)."), 'object_description': hasattr(obj, 'description') and obj.description or False, 'object_user': hasattr(obj, 'user_id') and (obj.user_id and obj.user_id.name) or '/', 'object_user_email': hasattr(obj, 'user_id') and (obj.user_id and \ - obj.user_id.user_email) or '/', + obj.user_id.email) or '/', 'object_user_phone': hasattr(obj, 'partner_address_id') and (obj.partner_address_id and \ obj.partner_address_id.phone) or '/', 'partner': hasattr(obj, 'partner_id') and (obj.partner_id and obj.partner_id.name) or '/', @@ -319,8 +319,8 @@ the rule to mark CC(mail to any other person defined in actions)."), mail_message = self.pool.get('mail.message') body = self.format_mail(obj, body) if not emailfrom: - if hasattr(obj, 'user_id') and obj.user_id and obj.user_id.user_email: - emailfrom = obj.user_id.user_email + if hasattr(obj, 'user_id') and obj.user_id and obj.user_id.email: + emailfrom = obj.user_id.email name = '[%d] %s' % (obj.id, tools.ustr(obj.name)) emailfrom = tools.ustr(emailfrom) @@ -419,7 +419,7 @@ the rule to mark CC(mail to any other person defined in actions)."), emails = [] if hasattr(obj, 'user_id') and action.act_mail_to_user: if obj.user_id: - emails.append(obj.user_id.user_email) + emails.append(obj.user_id.email) if action.act_mail_to_watchers: emails += (action.act_email_cc or '').split(',') diff --git a/addons/base_action_rule/base_action_rule_view.xml b/addons/base_action_rule/base_action_rule_view.xml index ba51b729305..0d268438a41 100644 --- a/addons/base_action_rule/base_action_rule_view.xml +++ b/addons/base_action_rule/base_action_rule_view.xml @@ -10,7 +10,6 @@ base.action.rule.form base.action.rule - form
@@ -98,7 +97,6 @@ base.action.rule.tree base.action.rule - tree diff --git a/addons/base_calendar/base_calendar.py b/addons/base_calendar/base_calendar.py index b570c2ef011..be3244f8a5b 100644 --- a/addons/base_calendar/base_calendar.py +++ b/addons/base_calendar/base_calendar.py @@ -245,7 +245,7 @@ class calendar_attendee(osv.osv): continue else: result[id][name] = self._get_address(attdata.sent_by_uid.name, \ - attdata.sent_by_uid.user_email) + attdata.sent_by_uid.email) if name == 'cn': if attdata.user_id: @@ -289,7 +289,7 @@ class calendar_attendee(osv.osv): if name == 'language': user_obj = self.pool.get('res.users') - lang = user_obj.read(cr, uid, uid, ['context_lang'], context=context)['context_lang'] + lang = user_obj.read(cr, uid, uid, ['lang'], context=context)['lang'] result[id][name] = lang.replace('_', '-') return result @@ -434,7 +434,7 @@ property or property parameter."), if not organizer: organizer = event_obj.user_id event_org.params['CN'] = [organizer.name] - event_org.value = 'MAILTO:' + (organizer.user_email or organizer.name) + event_org.value = 'MAILTO:' + (organizer.email or organizer.name) if event_obj.alarm_id: # computes alarm data @@ -535,7 +535,7 @@ property or property parameter."), return {'value': {'email': ''}} usr_obj = self.pool.get('res.users') user = usr_obj.browse(cr, uid, user_id, *args) - return {'value': {'email': user.user_email, 'availability':user.availability}} + return {'value': {'email': user.email, 'availability':user.availability}} def do_tentative(self, cr, uid, ids, context=None, *args): """ Makes event invitation as Tentative @@ -891,9 +891,9 @@ From: """ % (alarm.name, alarm.trigger_date, alarm.description, \ alarm.user_id.name, alarm.user_id.signature) - mail_to = [alarm.user_id.user_email] + mail_to = [alarm.user_id.email] for att in alarm.attendee_ids: - mail_to.append(att.user_id.user_email) + mail_to.append(att.user_id.email) if mail_to: mail_message.schedule_with_attach(cr, uid, tools.config.get('email_from', False), @@ -947,7 +947,7 @@ class calendar_event(osv.osv): value['duration'] = duration # change start_date's time to 00:00:00 in the user's timezone user = self.pool.get('res.users').browse(cr, uid, uid) - tz = pytz.timezone(user.context_tz) if user.context_tz else pytz.utc + tz = pytz.timezone(user.tz) if user.tz else pytz.utc start = pytz.utc.localize(start).astimezone(tz) # convert start in user's timezone start = start.replace(hour=0, minute=0, second=0) # change start's time to 00:00:00 start = start.astimezone(pytz.utc) # convert start back to utc @@ -1097,8 +1097,8 @@ rule or repeating pattern of time to exclude from the recurring rule."), user_pool = self.pool.get('res.users') user = user_pool.browse(cr, uid, uid, context=context) res = user.name - if user.user_email: - res += " <%s>" %(user.user_email) + if user.email: + res += " <%s>" %(user.email) return res _defaults = { diff --git a/addons/base_calendar/base_calendar_view.xml b/addons/base_calendar/base_calendar_view.xml index d48795173ed..89066ce74bb 100644 --- a/addons/base_calendar/base_calendar_view.xml +++ b/addons/base_calendar/base_calendar_view.xml @@ -6,13 +6,12 @@ calendar.attendee.form calendar.attendee - form
- + colspan="4" required="1"/> + + on_change="onchange_dates(date,duration,False,allday)"/> - + on_change="onchange_dates(date,False,date_deadline)"/> + + widget="selection"/> @@ -222,11 +216,11 @@ - + - - + + @@ -241,31 +235,31 @@ - - - + + +
- - - - - - - -
-
- - - - Dashboard Definition - board.board + + Create Board + board.create form - tree,form - + form + + new - - - diff --git a/addons/board/controllers.py b/addons/board/controllers.py new file mode 100644 index 00000000000..53845c96095 --- /dev/null +++ b/addons/board/controllers.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +from xml.etree import ElementTree + +try: + import openerp.addons.web.common.http as openerpweb + from openerp.addons.web.common import nonliterals + from openerp.addons.web.controllers.main import load_actions_from_ir_values +except ImportError: + import web.common.http as openerpweb # noqa + from web.common import nonliterals # noqa + from web.controllers.main import load_actions_from_ir_values # noqa + +class Board(openerpweb.Controller): + _cp_path = '/board' + + @openerpweb.jsonrequest + def add_to_dashboard(self, req, menu_id, action_id, context_to_save, domain, view_mode, name=''): + # FIXME move this method to board.board model + to_eval = nonliterals.CompoundContext(context_to_save) + to_eval.session = req.session + ctx = dict((k, v) for k, v in to_eval.evaluate().iteritems() + if not k.startswith('search_default_')) + ctx['dashboard_merge_domains_contexts'] = False # TODO: replace this 6.1 workaround by attribute on + domain = nonliterals.CompoundDomain(domain) + domain.session = req.session + domain = domain.evaluate() + + dashboard_action = load_actions_from_ir_values(req, 'action', 'tree_but_open', [('ir.ui.menu', menu_id)], False) + + if dashboard_action: + action = dashboard_action[0][2] + if action['res_model'] == 'board.board' and action['views'][0][1] == 'form': + # Maybe should check the content instead of model board.board ? + view_id = action['views'][0][0] + board = req.session.model(action['res_model']).fields_view_get(view_id, 'form') + if board and 'arch' in board: + xml = ElementTree.fromstring(board['arch']) + column = xml.find('./board/column') + if column is not None: + new_action = ElementTree.Element('action', { + 'name': str(action_id), + 'string': name, + 'view_mode': view_mode, + 'context': str(ctx), + 'domain': str(domain) + }) + column.insert(0, new_action) + arch = ElementTree.tostring(xml, 'utf-8') + return req.session.model('ir.ui.view.custom').create({ + 'user_id': req.session._uid, + 'ref_id': view_id, + 'arch': arch + }, req.session.eval_context(req.context)) + + return False diff --git a/addons/board/security/ir.model.access.csv b/addons/board/security/ir.model.access.csv index ec9d2e89f4b..4833c8ded0f 100644 --- a/addons/board/security/ir.model.access.csv +++ b/addons/board/security/ir.model.access.csv @@ -1,3 +1,2 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_board_board all,board.board,model_board_board,,1,0,0,0 -access_board_board system,board.board system,model_board_board,base.group_system,1,1,1,1 diff --git a/addons/board/static/src/css/dashboard.css b/addons/board/static/src/css/dashboard.css new file mode 100644 index 00000000000..f3d300add2e --- /dev/null +++ b/addons/board/static/src/css/dashboard.css @@ -0,0 +1,73 @@ +.openerp .oe_dashboard_links { + text-align: right; + margin: 0 4px 6px 0; +} +.openerp .oe_dashboard { + width: 100%; +} +.openerp .oe_dashboard .oe_action { + margin: 0 8px 8px 0; + background-color: white; + border: 1px solid; + border-color: #e5e5e5 #dbdbdb #d2d2d2; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + border-radius: 3px; + -moz-box-shadow: 0 0 2px rgba(0, 0, 0, 0.2); + -webkit-box-shadow: 0 0 2px rgba(0, 0, 0, 0.2); + box-shadow: 0 0 2px rgba(0, 0, 0, 0.2); +} +.openerp .oe_dashboard .oe_action .oe_header { + font-size: 16px; + vertical-align: middle; + margin: 0; + padding: 12px; + -moz-border-radius: 3px 3px 0 0; + -webkit-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; +} +.openerp .oe_dashboard .oe_action .oe_header:hover { + cursor: move; +} +.openerp .oe_dashboard .oe_action .oe_header .oe_icon { + float: right; + cursor: pointer; + color: #b3b3b3; +} +.openerp .oe_dashboard .oe_action .oe_header .oe_icon:hover { + color: #666666; + text-decoration: none; +} +.openerp .oe_dashboard .oe_action .oe_header .oe_close:after { + content: "×"; + margin-left: 4px; +} +.openerp .oe_dashboard .oe_action .oe_header .oe_minimize:after { + content: "-"; + margin-left: 4px; +} +.openerp .oe_dashboard .oe_action .oe_header .oe_maximize:after { + content: "+"; + margin-left: 4px; +} +.openerp .oe_dashboard .oe_action .oe_header_empty { + padding-top: 0; + padding-bottom: 2px; +} +.openerp .oe_dashboard .oe_action .oe_button_create { + margin-left: 4px; + padding: 0 4px 0 4px; + height: 16px !important; +} +.openerp .oe_dashboard .oe_action .oe_content { + padding: 0 12px 12px 12px; +} +.openerp .oe_dashboard .oe_action .oe_content .oe_view_manager_header { + display: none; +} +.openerp .oe_dashboard .oe_action .oe_content .oe_list_content > thead { + border-bottom: 1px; +} +.openerp .oe_dashboard .oe_action .oe_content .oe_list_content > tbody tr:nth-child(odd) { + background: transparent; +} diff --git a/addons/board/static/src/css/dashboard.sass b/addons/board/static/src/css/dashboard.sass new file mode 100644 index 00000000000..dd4d144e918 --- /dev/null +++ b/addons/board/static/src/css/dashboard.sass @@ -0,0 +1,83 @@ +@mixin radius($radius: 5px) + -moz-border-radius: $radius + -webkit-border-radius: $radius + border-radius: $radius + +@mixin box-shadow($bsval: 0px 1px 4px #777) + -moz-box-shadow: $bsval + -webkit-box-shadow: $bsval + box-shadow: $bsval + +.openerp + .oe_dashboard_links + text-align: right + margin: 0 4px 6px 0 + .oe_dashboard + width: 100% + .oe_action + margin: 0 8px 8px 0 + background-color: white + border: 1px solid + border-color: #e5e5e5 #dbdbdb #d2d2d2 + @include radius(3px) + @include box-shadow(0 0 2px rgba(0,0,0,0.2)) + .oe_header + font-size: 16px + vertical-align: middle + margin: 0 + padding: 12px + @include radius(3px 3px 0 0) + + //border-bottom: 1px dotted #dbdbdb + //@include radius(2px 2px 0 0) + //@include vertical-gradient(#FCFCFC, #DEDEDE) + &:hover + cursor: move + .oe_icon + float: right + cursor: pointer + color: #b3b3b3 + &:hover + color: #666 + text-decoration: none + .oe_close:after + content: "×" + margin-left: 4px + .oe_minimize:after + content: "-" + margin-left: 4px + .oe_maximize:after + content: "+" + margin-left: 4px + .oe_header_empty + padding-top: 0 + padding-bottom: 2px + .oe_button_create + margin-left: 4px + padding: 0 4px 0 4px + height: 16px !important + //.oe_rename + //float: left + //padding-right: 4px + //position: relative + //top: 1px + //.oe_input + //height: 16px; + //position: relative; + //top: 2px; + //.ui-sortable-placeholder + //border: 1px dotted black; + //visibility: visible !important; + //height: 50px !important; + //* + //visibility: hidden; + .oe_content + padding: 0 12px 12px 12px + .oe_view_manager_header + display: none + .oe_list_content + > thead + border-bottom: 1px + > tbody + tr:nth-child(odd) + background: transparent diff --git a/addons/board/static/src/img/layout_1-1-1.png b/addons/board/static/src/img/layout_1-1-1.png new file mode 100644 index 00000000000..5eda2823c46 Binary files /dev/null and b/addons/board/static/src/img/layout_1-1-1.png differ diff --git a/addons/board/static/src/img/layout_1-1.png b/addons/board/static/src/img/layout_1-1.png new file mode 100644 index 00000000000..e72aa3a0533 Binary files /dev/null and b/addons/board/static/src/img/layout_1-1.png differ diff --git a/addons/board/static/src/img/layout_1-2.png b/addons/board/static/src/img/layout_1-2.png new file mode 100644 index 00000000000..4b14d7aeaad Binary files /dev/null and b/addons/board/static/src/img/layout_1-2.png differ diff --git a/addons/board/static/src/img/layout_1.png b/addons/board/static/src/img/layout_1.png new file mode 100644 index 00000000000..69a0e30854c Binary files /dev/null and b/addons/board/static/src/img/layout_1.png differ diff --git a/addons/board/static/src/img/layout_2-1.png b/addons/board/static/src/img/layout_2-1.png new file mode 100644 index 00000000000..ed866add47c Binary files /dev/null and b/addons/board/static/src/img/layout_2-1.png differ diff --git a/addons/board/static/src/img/view_todo_arrow.png b/addons/board/static/src/img/view_todo_arrow.png new file mode 100644 index 00000000000..8633430e9ae Binary files /dev/null and b/addons/board/static/src/img/view_todo_arrow.png differ diff --git a/addons/board/static/src/js/dashboard.js b/addons/board/static/src/js/dashboard.js new file mode 100644 index 00000000000..b9df81bf868 --- /dev/null +++ b/addons/board/static/src/js/dashboard.js @@ -0,0 +1,378 @@ +openerp.board = function(instance) { +var QWeb = instance.web.qweb, + _t = instance.web._t; + +if (!instance.board) { + /** @namespace */ + instance.board = {}; +} + +instance.web.form.DashBoard = instance.web.form.FormWidget.extend({ + init: function(view, node) { + this._super(view, node); + this.form_template = 'DashBoard'; + this.actions_attrs = {}; + this.action_managers = []; + }, + start: function() { + var self = this; + this._super.apply(this, arguments); + + this.$element.find('.oe_dashboard_column').sortable({ + connectWith: '.oe_dashboard_column', + handle: '.oe_header', + scroll: false + }).disableSelection().bind('sortstop', self.do_save_dashboard); + + // Events + this.$element.find('.oe_dashboard_link_reset').click(this.on_reset); + this.$element.find('.oe_dashboard_link_change_layout').click(this.on_change_layout); + + this.$element.delegate('.oe_dashboard_column .oe_fold', 'click', this.on_fold_action); + this.$element.delegate('.oe_dashboard_column .oe_close', 'click', this.on_close_action); + + // Init actions + _.each(this.node.children, function(column, column_index) { + _.each(column.children, function(action, action_index) { + delete(action.attrs.width); + delete(action.attrs.height); + delete(action.attrs.colspan); + var action_id = _.str.toNumber(action.attrs.name); + if (!_.isNaN(action_id)) { + self.rpc('/web/action/load', {action_id: action_id}, function(result) { + self.on_load_action(result, column_index + '_' + action_index, action.attrs); + }); + } + }); + }); + }, + on_reset: function() { + this.rpc('/web/view/undo_custom', { + view_id: this.view.fields_view.view_id, + reset: true + }, this.do_reload); + }, + on_change_layout: function() { + var self = this; + var qdict = { + current_layout : this.$element.find('.oe_dashboard').attr('data-layout') + }; + var $dialog = instance.web.dialog($('
'), { + modal: true, + title: _t("Edit Layout"), + width: 'auto', + height: 'auto' + }).html(QWeb.render('DashBoard.layouts', qdict)); + $dialog.find('li').click(function() { + var layout = $(this).attr('data-layout'); + $dialog.dialog('destroy'); + self.do_change_layout(layout); + }); + }, + do_change_layout: function(new_layout) { + var $dashboard = this.$element.find('.oe_dashboard'); + var current_layout = $dashboard.attr('data-layout'); + if (current_layout != new_layout) { + var clayout = current_layout.split('-').length, + nlayout = new_layout.split('-').length, + column_diff = clayout - nlayout; + if (column_diff > 0) { + var $last_column = $(); + $dashboard.find('.oe_dashboard_column').each(function(k, v) { + if (k >= nlayout) { + $(v).find('.oe_action').appendTo($last_column); + } else { + $last_column = $(v); + } + }); + } + $dashboard.toggleClass('oe_dashboard_layout_' + current_layout + ' oe_dashboard_layout_' + new_layout); + $dashboard.attr('data-layout', new_layout); + this.do_save_dashboard(); + } + }, + on_fold_action: function(e) { + var $e = $(e.currentTarget), + $action = $e.parents('.oe_action:first'), + id = parseInt($action.attr('data-id'), 10); + if ($e.is('.oe_minimize')) { + $action.data('action_attrs').fold = '1'; + } else { + delete($action.data('action_attrs').fold); + } + $e.toggleClass('oe_minimize oe_maximize'); + $action.find('.oe_content').toggle(); + this.do_save_dashboard(); + }, + on_close_action: function(e) { + if (confirm(_t("Are you sure you want to remove this item ?"))) { + $(e.currentTarget).parents('.oe_action:first').remove(); + this.do_save_dashboard(); + } + }, + do_save_dashboard: function() { + var self = this; + var board = { + form_title : this.view.fields_view.arch.attrs.string, + style : this.$element.find('.oe_dashboard').attr('data-layout'), + columns : [] + }; + this.$element.find('.oe_dashboard_column').each(function() { + var actions = []; + $(this).find('.oe_action').each(function() { + var action_id = $(this).attr('data-id'), + new_attrs = _.clone($(this).data('action_attrs')); + if (new_attrs.domain) { + new_attrs.domain = new_attrs.domain_string; + delete(new_attrs.domain_string); + } + if (new_attrs.context) { + new_attrs.context = new_attrs.context_string; + delete(new_attrs.context_string); + } + actions.push(new_attrs); + }); + board.columns.push(actions); + }); + var arch = QWeb.render('DashBoard.xml', board); + this.rpc('/web/view/add_custom', { + view_id: this.view.fields_view.view_id, + arch: arch + }, function() { + self.$element.find('.oe_dashboard_link_reset').show(); + }); + }, + on_load_action: function(result, index, action_attrs) { + var self = this, + action = result.result, + view_mode = action_attrs.view_mode; + + if (action_attrs.context && action_attrs.context['dashboard_merge_domains_contexts'] === false) { + // TODO: replace this 6.1 workaround by attribute on + action.context = action_attrs.context || {}; + action.domain = action_attrs.domain || []; + } else { + if (action_attrs.context) { + action.context = _.extend((action.context || {}), action_attrs.context); + } + if (action_attrs.domain) { + action.domain = action.domain || []; + action.domain.unshift.apply(action.domain, action_attrs.domain); + } + } + + var action_orig = _.extend({ flags : {} }, action); + + if (view_mode && view_mode != action.view_mode) { + action.views = _.map(view_mode.split(','), function(mode) { + mode = mode === 'tree' ? 'list' : mode; + return _(action.views).find(function(view) { return view[1] == mode; }) + || [false, mode]; + }); + } + + action.flags = { + search_view : false, + sidebar : false, + views_switcher : false, + action_buttons : false, + pager: false, + low_profile: true, + display_title: false, + list: { + selectable: false + } + }; + var am = new instance.web.ActionManager(this), + // FIXME: ideally the dashboard view shall be refactored like kanban. + $action = $('#' + this.view.element_id + '_action_' + index); + $action.parent().data('action_attrs', action_attrs); + this.action_managers.push(am); + am.appendTo($action); + am.do_action(action); + am.do_action = function (action) { + self.do_action(action); + }; + if (action_attrs.creatable && action_attrs.creatable !== 'false') { + var action_id = parseInt(action_attrs.creatable, 10); + $action.parent().find('button.oe_dashboard_button_create').click(function() { + if (isNaN(action_id)) { + action_orig.flags.default_view = 'form'; + self.do_action(action_orig); + } else { + self.rpc('/web/action/load', { + action_id: action_id + }, function(result) { + result.result.flags = result.result.flags || {}; + result.result.flags.default_view = 'form'; + self.do_action(result.result); + }); + } + }); + } + if (am.inner_widget) { + am.inner_widget.on_mode_switch.add(function(mode) { + var new_views = []; + _.each(action_orig.views, function(view) { + new_views[view[1] === mode ? 'unshift' : 'push'](view); + }); + if (!new_views.length || new_views[0][1] !== mode) { + new_views.unshift([false, mode]); + } + action_orig.views = new_views; + action_orig.res_id = am.inner_widget.dataset.ids[am.inner_widget.dataset.index]; + self.do_action(action_orig); + }); + } + }, + renderElement: function() { + this._super(); + + var check = _.detect(this.node.children, function(column, column_index) { + return _.detect(column.children,function(element){ + return element.tag === "action"? element: false; + }); + }); + if (!check) { + return this.no_result(); + } + // We should start with three columns available + for (var i = this.node.children.length; i < 3; i++) { + this.node.children.push({ + tag: 'column', + attrs: {}, + children: [] + }); + } + var rendered = QWeb.render(this.form_template, this); + this.$element.html(rendered); + }, + no_result: function() { + if (this.view.options.action.help) { + this.$element.append( + $('
') + .append($('
').html(this.view.options.action.help || " ")) + ); + } + }, + do_reload: function() { + var view_manager = this.view.getParent(), + action_manager = view_manager.getParent(); + this.view.destroy(); + action_manager.do_action(view_manager.action); + } +}); +instance.web.form.DashBoardLegacy = instance.web.form.DashBoard.extend({ + renderElement: function() { + if (this.node.tag == 'hpaned') { + this.node.attrs.style = '2-1'; + } else if (this.node.tag == 'vpaned') { + this.node.attrs.style = '1'; + } + this.node.tag = 'board'; + _.each(this.node.children, function(child) { + if (child.tag.indexOf('child') == 0) { + child.tag = 'column'; + var actions = [], first_child = child.children[0]; + if (first_child && first_child.tag == 'vpaned') { + _.each(first_child.children, function(subchild) { + actions.push.apply(actions, subchild.children); + }); + child.children = actions; + } + } + }); + this._super(this); + } +}); + +instance.web.form.tags.add('hpaned', 'instance.web.form.DashBoardLegacy'); +instance.web.form.tags.add('vpaned', 'instance.web.form.DashBoardLegacy'); +instance.web.form.tags.add('board', 'instance.web.form.DashBoard'); + + +instance.board.AddToDashboard = instance.web.search.Input.extend({ + template: 'SearchView.addtodashboard', + _in_drawer: true, + start: function () { + var self = this; + this.$element + .on('click', 'h4', this.proxy('show_option')) + .on('submit', 'form', function (e) { + e.preventDefault(); + self.add_dashboard(); + }); + return this.load_data().then(this.proxy("render_data")); + }, + load_data:function(){ + var board = new instance.web.Model('board.board'); + return board.call('list'); + }, + _x:function() { + if (!instance.webclient) { return $.Deferred().reject(); } + var dashboard_menu = instance.webclient.menu.data.data.children; + return new instance.web.Model('ir.model.data') + .query(['res_id']) + .filter([['name','=','menu_reporting_dashboard']]) + .first().pipe(function (result) { + var menu = _(dashboard_menu).chain() + .pluck('children') + .flatten(true) + .find(function (child) { return child.id === result.res_id; }) + .value(); + return menu ? menu.children : []; + }); + }, + render_data: function(dashboard_choices){ + var selection = instance.web.qweb.render( + "SearchView.addtodashboard.selection", { + selections: dashboard_choices}); + this.$("input").before(selection) + }, + add_dashboard: function(){ + var self = this; + var getParent = this.getParent(); + var view_parent = this.getParent().getParent(); + if (! view_parent.action || ! this.$element.find("select").val()) { + this.do_warn("Can't find dashboard action"); + return; + } + var data = getParent.build_search_data(); + var context = new instance.web.CompoundContext(getParent.dataset.get_context() || []); + var domain = new instance.web.CompoundDomain(getParent.dataset.get_domain() || []); + _.each(data.contexts, context.add, context); + _.each(data.domains, domain.add, domain); + this.rpc('/board/add_to_dashboard', { + menu_id: this.$element.find("select").val(), + action_id: view_parent.action.id, + context_to_save: context, + domain: domain, + view_mode: view_parent.active_view, + name: this.$element.find("input").val() + }, function(r) { + if (r === false) { + self.do_warn("Could not add filter to dashboard"); + } else { + self.$element.toggleClass('oe_opened'); + self.do_notify("Filter added to dashboard", ''); + } + }); + }, + show_option:function(){ + this.$element.toggleClass('oe_opened'); + if (! this.$element.hasClass('oe_opened')) + return; + this.$("input").val(this.getParent().fields_view.name || "" ); + } +}); + + +instance.web.SearchView.include({ + add_common_inputs: function() { + this._super(); + (new instance.board.AddToDashboard(this)); + + } +}); + +}; diff --git a/addons/board/static/src/xml/board.xml b/addons/board/static/src/xml/board.xml new file mode 100644 index 00000000000..13d81d11f8d --- /dev/null +++ b/addons/board/static/src/xml/board.xml @@ -0,0 +1,80 @@ +