summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorGéry Debongnie <ged@odoo.com>2015-06-15 16:31:27 +0200
committerGéry Debongnie <ged@odoo.com>2015-06-15 16:31:27 +0200
commit2c7367a8cc8d9e200b1fa2083ce0d80f8f4e4bd3 (patch)
treeaf916cff4d94554b1e9667913e3feb331ec81a13 /addons
parent5cb10d4fc9594f0c6825757c24d66d63664ce026 (diff)
parent82186a93bb3f93c36667835df68fa31dcacf97a2 (diff)
[MERGE] new kanban view
This branch introduces the new kanban view. It is not completely compatible with the previous version. Here are a few importants points to be aware of: * the kanban view template is rendered directly, not put inside a div. It means that if a template has more than one root, chaos will ensue * kanban view has been split into several files, and various js modules have changed. For example, the KanbanRecord class is now exported by the 'web_kanban.Record' module. So, require statements need to be updated * records do not have access to the view (i.e., record.view.is_action_enabled('edit')) You can use the 'editable' and 'deletable' key instead
Diffstat (limited to 'addons')
-rw-r--r--addons/account/static/src/js/account_journal_dashboard_widget.js6
-rw-r--r--addons/account/views/account_journal_dashboard_view.xml2
-rw-r--r--addons/account/views/account_payment_view.xml9
-rw-r--r--addons/account/views/account_view.xml4
-rw-r--r--addons/account/views/partner_view.xml41
-rw-r--r--addons/account_analytic_analysis/account_analytic_analysis_view.xml8
-rw-r--r--addons/account_analytic_default/account_analytic_default_view.xml12
-rw-r--r--addons/account_asset/views/account_asset_view.xml8
-rw-r--r--addons/analytic/views/analytic_view.xml3
-rw-r--r--addons/auth_signup/res_users_view.xml2
-rw-r--r--addons/base_setup/res_partner_view.xml2
-rw-r--r--addons/crm/crm_lead_view.xml55
-rw-r--r--addons/crm/crm_phonecall_view.xml23
-rw-r--r--addons/crm/res_partner_view.xml19
-rw-r--r--addons/crm_claim/res_partner_view.xml8
-rw-r--r--addons/crm_project_issue/project_issue_view.xml13
-rw-r--r--addons/event/event_view.xml14
-rw-r--r--addons/fleet/fleet_view.xml28
-rw-r--r--addons/gamification/views/badge.xml3
-rw-r--r--addons/gamification/views/challenge.xml23
-rw-r--r--addons/hr/hr_dashboard.xml2
-rw-r--r--addons/hr/hr_view.xml82
-rw-r--r--addons/hr/static/src/js/hr.js8
-rw-r--r--addons/hr/static/src/less/hr_dashboard.less16
-rw-r--r--addons/hr/views/hr.xml1
-rw-r--r--addons/hr_contract/hr_contract_view.xml4
-rw-r--r--addons/hr_equipment/views/hr_equipment_views.xml36
-rw-r--r--addons/hr_evaluation/hr_evaluation_view.xml6
-rw-r--r--addons/hr_gamification/static/src/js/gamification.js6
-rw-r--r--addons/hr_gamification/views/gamification.xml4
-rw-r--r--addons/hr_holidays/hr_holidays_view.xml4
-rw-r--r--addons/hr_payroll/hr_payroll_view.xml6
-rw-r--r--addons/hr_recruitment/hr_recruitment_dashboard.xml2
-rw-r--r--addons/hr_recruitment/hr_recruitment_view.xml103
-rw-r--r--addons/hr_recruitment/static/src/js/job_position.js6
-rw-r--r--addons/hr_timesheet/hr_timesheet_view.xml6
-rw-r--r--addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml11
-rw-r--r--addons/im_livechat/views/im_livechat_channel_views.xml16
-rw-r--r--addons/mail/views/mail_alias_views.xml4
-rw-r--r--addons/mail/views/mail_template_views.xml30
-rw-r--r--addons/marketing_campaign/marketing_campaign_view.xml7
-rw-r--r--addons/mass_mailing/static/src/js/mass_mailing.js6
-rw-r--r--addons/mass_mailing/views/email_template.xml20
-rw-r--r--addons/mass_mailing/views/mass_mailing.xml80
-rw-r--r--addons/mrp/mrp_view.xml12
-rw-r--r--addons/note/note_view.xml46
-rw-r--r--addons/point_of_sale/point_of_sale_view.xml12
-rw-r--r--addons/procurement/procurement_view.xml8
-rw-r--r--addons/product/product_view.xml45
-rw-r--r--addons/project/project.py10
-rw-r--r--addons/project/project_dashboard.xml10
-rw-r--r--addons/project/project_view.xml68
-rw-r--r--addons/project/res_partner_view.xml12
-rw-r--r--addons/project/static/src/js/project.js6
-rw-r--r--addons/project/static/src/less/project_dashboard.less58
-rw-r--r--addons/project_issue/project_issue_view.xml22
-rw-r--r--addons/project_timesheet/project_timesheet_view.xml6
-rw-r--r--addons/purchase/partner_view.xml12
-rw-r--r--addons/purchase/purchase_view.xml12
-rw-r--r--addons/purchase/stock_view.xml2
-rw-r--r--addons/purchase_requisition/purchase_requisition_view.xml10
-rw-r--r--addons/rating/static/src/js/rating.js6
-rw-r--r--addons/rating_project/views/project_view.xml6
-rw-r--r--addons/rating_project_issue/views/project_issue_view.xml4
-rw-r--r--addons/sale/res_partner_view.xml11
-rw-r--r--addons/sale/sale_view.xml28
-rw-r--r--addons/sale_crm/sale_crm_view.xml14
-rw-r--r--addons/sales_team/sales_team_dashboard.xml2
-rw-r--r--addons/sales_team/static/src/js/sales_team.js6
-rw-r--r--addons/stock/product_view.xml20
-rw-r--r--addons/stock/stock_dashboard.xml2
-rw-r--r--addons/stock/stock_view.xml32
-rw-r--r--addons/stock_picking_wave/stock_picking_wave_view.xml2
-rw-r--r--addons/survey/views/survey_views.xml7
-rw-r--r--addons/web/static/src/js/framework/core.js5
-rw-r--r--addons/web/static/src/js/views/form_widgets.js3
-rw-r--r--addons/web/static/src/js/widgets/pager.js111
-rw-r--r--addons/web/static/src/less/enterprise_compatibility.less195
-rw-r--r--addons/web/static/src/less/utils.less189
-rw-r--r--addons/web/static/src/xml/base.xml23
-rw-r--r--addons/web/views/webclient_templates.xml3
-rw-r--r--addons/web_kanban/static/src/css/kanban.css8
-rw-r--r--addons/web_kanban/static/src/css/kanban.sass2
-rw-r--r--addons/web_kanban/static/src/js/compatibility.js10
-rw-r--r--addons/web_kanban/static/src/js/kanban_column.js245
-rw-r--r--addons/web_kanban/static/src/js/kanban_common.js928
-rw-r--r--addons/web_kanban/static/src/js/kanban_quick_create.js127
-rw-r--r--addons/web_kanban/static/src/js/kanban_record.js275
-rw-r--r--addons/web_kanban/static/src/js/kanban_view.js1153
-rw-r--r--addons/web_kanban/static/src/js/kanban_widgets.js247
-rw-r--r--addons/web_kanban/static/src/less/kanban_dashboard.less49
-rw-r--r--addons/web_kanban/static/src/less/kanban_view.less500
-rw-r--r--addons/web_kanban/static/src/xml/web_kanban.xml138
-rw-r--r--addons/web_kanban/views/web_kanban.xml7
-rw-r--r--addons/web_kanban_gauge/static/src/js/kanban_gauge.js6
-rw-r--r--addons/web_tests/tests/test_ui.py2
-rw-r--r--addons/website/static/src/css/website.backend.css6
-rw-r--r--addons/website/static/src/js/website.backend.js9
-rw-r--r--addons/website/static/src/xml/website.backend.xml10
-rw-r--r--addons/website_blog/views/website_blog_views.xml4
-rw-r--r--addons/website_crm_partner_assign/views/partner_grade.xml4
-rw-r--r--addons/website_crm_score/static/src/js/display_filters.js6
-rw-r--r--addons/website_crm_score/views/marketing.xml4
-rw-r--r--addons/website_crm_score/views/sales.xml15
-rw-r--r--addons/website_event/views/website_event_backend.xml10
-rw-r--r--addons/website_event_track/views/event_backend.xml20
-rw-r--r--addons/website_forum/views/res_users.xml6
-rw-r--r--addons/website_forum_doc/views/doc.xml4
-rw-r--r--addons/website_hr/views/website_hr_view.xml6
-rw-r--r--addons/website_hr_recruitment/views/hr_job_views.xml6
-rw-r--r--addons/website_links/views/website_links.xml2
-rw-r--r--addons/website_livechat/views/website_livechat_view.xml6
-rw-r--r--addons/website_partner/views/res_partner_view.xml8
-rw-r--r--addons/website_sale/views/views.xml6
-rw-r--r--addons/website_slides/view/website_slides_backend.xml18
-rw-r--r--addons/website_version/views/marketing_view.xml4
116 files changed, 3349 insertions, 2271 deletions
diff --git a/addons/account/static/src/js/account_journal_dashboard_widget.js b/addons/account/static/src/js/account_journal_dashboard_widget.js
index 9818309403e..c152a90442d 100644
--- a/addons/account/static/src/js/account_journal_dashboard_widget.js
+++ b/addons/account/static/src/js/account_journal_dashboard_widget.js
@@ -1,9 +1,9 @@
odoo.define('journal_dashboard', function (require) {
'use strict';
-var kanban_common = require('web_kanban.common');
+var kanban_widgets = require('web_kanban.widgets');
-var JournalDashboardGraph = kanban_common.AbstractField.extend({
+var JournalDashboardGraph = kanban_widgets.AbstractField.extend({
start: function() {
var self = this;
self.graph_type = self.$node.attr('graph_type')
@@ -86,6 +86,6 @@ var JournalDashboardGraph = kanban_common.AbstractField.extend({
});
-kanban_common.registry.add('dashboard_graph', JournalDashboardGraph);
+kanban_widgets.registry.add('dashboard_graph', JournalDashboardGraph);
}); \ No newline at end of file
diff --git a/addons/account/views/account_journal_dashboard_view.xml b/addons/account/views/account_journal_dashboard_view.xml
index 78ccd40bcb7..5ebe9e36659 100644
--- a/addons/account/views/account_journal_dashboard_view.xml
+++ b/addons/account/views/account_journal_dashboard_view.xml
@@ -194,7 +194,7 @@
<a type="object" name="toggle_favorite"><i t-att-class="(record.show_on_dashboard.raw_value ? 'oe_star_on' : 'oe_star_off') + ' fa fa-star o_dashboard_star'" title="Click to add/remove from favorite"></i></a>
</div>
<div class="col-xs-6 text-right">
- <a t-if="widget.view.is_action_enabled('edit')" type="edit">Settings</a>
+ <a t-if="widget.editable" type="edit">Settings</a>
</div>
</div>
</t>
diff --git a/addons/account/views/account_payment_view.xml b/addons/account/views/account_payment_view.xml
index a413a55477e..7a53640131e 100644
--- a/addons/account/views/account_payment_view.xml
+++ b/addons/account/views/account_payment_view.xml
@@ -79,12 +79,13 @@
<field name="state" widget="statusbar" statusbar_visible="posted,reconciled"/>
</header>
<sheet>
- <div class="oe_right oe_button_box">
- <button class="oe_inline oe_stat_button" name="button_journal_entries"
- string="Journal Items" type="object" groups="account.group_account_manager"
+ <div class="oe_button_box" name="button_box">
+ <button class="oe_stat_button" name="button_journal_entries"
+ string="Journal Items" type="object"
+ groups="account.group_account_manager"
attrs="{'invisible':[('move_line_ids','=',[])]}" icon="fa-bars"/>
<field name="move_line_ids" invisible="1"/>
- <button class="oe_inline oe_stat_button" name="button_invoices"
+ <button class="oe_stat_button" name="button_invoices"
string="Invoices" type="object"
attrs="{'invisible':[('has_invoices','=',False)]}" icon="fa-bars"/>
<field name="has_invoices" invisible="1"/>
diff --git a/addons/account/views/account_view.xml b/addons/account/views/account_view.xml
index 9bb4c45df0d..3cb209eecbf 100644
--- a/addons/account/views/account_view.xml
+++ b/addons/account/views/account_view.xml
@@ -442,8 +442,8 @@
<field name="state" widget="statusbar" statusbar_visible="open,confirm"/>
</header>
<sheet>
- <div class="oe_right oe_button_box" name="import_buttons">
- <button class="oe_inline oe_stat_button" name="button_journal_entries"
+ <div class="oe_button_box" name="button_box">
+ <button class="oe_stat_button" name="button_journal_entries"
string="Journal Items" type="object"
attrs="{'invisible':[('move_line_ids','=',[])]}" icon="fa-bars"/>
<field name="move_line_ids" invisible="1"/>
diff --git a/addons/account/views/partner_view.xml b/addons/account/views/partner_view.xml
index c4299986216..ab6bfcf4118 100644
--- a/addons/account/views/partner_view.xml
+++ b/addons/account/views/partner_view.xml
@@ -77,7 +77,7 @@
<field name="priority" eval="20"/>
<field name="groups_id" eval="[(4, ref('account.group_account_invoice'))]"/>
<field name="arch" type="xml">
- <xpath expr="//div[@name='buttons']" position="inside">
+ <div name="button_box" position="inside">
<button type="action"
class="oe_stat_button"
id="invoice_button"
@@ -85,10 +85,13 @@
name="%(account.action_invoice_refund_out_tree)d"
attrs="{'invisible': [('customer', '=', False)]}"
context="{'search_default_partner_id': active_id,'default_partner_id': active_id}">
- <div><strong><field name="total_invoiced"/></strong><br/>Invoiced</div>
+ <div class="o_form_field o_stat_info">
+ <span class="o_stat_value"><field name="total_invoiced"/></span>
+ <span class="o_stat_text">Invoiced</span>
+ </div>
</button>
<field name="currency_id" invisible="1"/>
- </xpath>
+ </div>
</field>
</record>
@@ -99,12 +102,12 @@
<field name="priority" eval="22"/>
<field name="groups_id" eval="[(4, ref('analytic.group_analytic_accounting'))]"/>
<field name="arch" type="xml">
- <xpath expr="//div[@name='buttons']" position="inside">
- <button class="oe_inline oe_stat_button" type="action" name="%(account.action_open_partner_analytic_accounts)d"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" type="action" name="%(account.action_open_partner_analytic_accounts)d"
icon="fa-book">
<field string="Contracts" name="contracts_count" widget="statinfo"/>
</button>
- </xpath>
+ </div>
</field>
</record>
@@ -132,10 +135,10 @@
<field name="groups_id" eval="[(4, ref('account.group_account_invoice'))]"/>
<field name="arch" type="xml">
<page name="sales_purchases" position="after">
- <page string="Accounting" col="4" name="accounting" attrs="{'invisible': [('is_company','=',False),('parent_id','!=',False)]}">
+ <page string="Accounting" name="accounting" attrs="{'invisible': [('is_company','=',False),('parent_id','!=',False)]}">
<group>
<group string="Sale" name="acc_sale">
- <button name="%(action_account_partner_followup_note)d" type="action" string="Log a followup note"/><br />
+ <button name="%(action_account_partner_followup_note)d" class="oe_link" type="action" string="Log a followup note" colspan="2"/>
<field name="property_payment_term" widget="selection"/>
<field name="credit"/>
<field name="credit_limit"/>
@@ -154,16 +157,16 @@
</group>
</group>
<group string="Bank Accounts" name="bank_accounts">
- <field name="bank_ids" context="{'default_partner_id': active_id, 'form_view_ref': 'base.view_partner_bank_form'}" nolabel="1">
- <tree string="Bank Details">
- <field name="state" invisible="1"/>
- <field name="sequence" invisible="1"/>
- <field name="acc_number"/>
- <field name="bank_name"/>
- <field name="owner_name"/>
- </tree>
- </field>
- </group>
+ <field name="bank_ids" context="{'default_partner_id': active_id, 'form_view_ref': 'base.view_partner_bank_form'}" nolabel="1">
+ <tree string="Bank Details">
+ <field name="state" invisible="1"/>
+ <field name="sequence" invisible="1"/>
+ <field name="acc_number"/>
+ <field name="bank_name"/>
+ <field name="owner_name"/>
+ </tree>
+ </field>
+ </group>
</page>
<page string="Accounting" name="accounting_disabled" attrs="{'invisible': ['|',('is_company','=',True),('parent_id','=',False)]}">
<div>
@@ -174,4 +177,4 @@
</field>
</record>
</data>
-</openerp>
+</openerp> \ No newline at end of file
diff --git a/addons/account_analytic_analysis/account_analytic_analysis_view.xml b/addons/account_analytic_analysis/account_analytic_analysis_view.xml
index b7a9c1973fa..c9f18cb7fee 100644
--- a/addons/account_analytic_analysis/account_analytic_analysis_view.xml
+++ b/addons/account_analytic_analysis/account_analytic_analysis_view.xml
@@ -374,18 +374,18 @@
<field name="inherit_id" ref="analytic.view_account_analytic_account_form"/>
<field eval="20" name="priority"/>
<field name="arch" type="xml">
- <xpath expr='//div[@name="buttons"]' position='inside'>
- <button class="oe_inline oe_stat_button"
+ <div name="button_box" position='inside'>
+ <button class="oe_stat_button"
string="To invoice"
icon="fa-money"
name="%(action_hr_tree_invoiced_all)d"
type="action"
context="{'search_default_account_id': [active_id], 'default_account_id': active_id}"/>
- <button class="oe_inline oe_stat_button" string="Invoices"
+ <button class="oe_stat_button" string="Invoices"
icon="fa-book"
name="%(action_contract_invoices_all)d"
type="action"/>
- </xpath>
+ </div>
</field>
</record>
diff --git a/addons/account_analytic_default/account_analytic_default_view.xml b/addons/account_analytic_default/account_analytic_default_view.xml
index fd38be3165d..c43ddff78e0 100644
--- a/addons/account_analytic_default/account_analytic_default_view.xml
+++ b/addons/account_analytic_default/account_analytic_default_view.xml
@@ -79,12 +79,12 @@
<field name="model">product.product</field>
<field name="inherit_id" ref="product.product_normal_form_view"/>
<field name="arch" type="xml">
- <xpath expr="//div[@name='buttons']" position="inside">
- <button class="oe_inline oe_stat_button" name= "%(action_product_default_list)d" type="action"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" name= "%(action_product_default_list)d" type="action"
groups="analytic.group_analytic_accounting" icon="fa-xing">
<field string="Analytic Rules" name="rules_count" widget="statinfo" />
</button>
- </xpath>
+ </div>
</field>
</record>
@@ -93,12 +93,12 @@
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_only_form_view"/>
<field name="arch" type="xml">
- <xpath expr="//div[@name='buttons']" position="inside">
- <button class="oe_inline oe_stat_button" name= "action_view_rules" type="object"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" name= "action_view_rules" type="object"
groups="analytic.group_analytic_accounting" icon="fa-xing">
<field string="Analytic Rules" name="rules_count" widget="statinfo" />
</button>
- </xpath>
+ </div>
</field>
</record>
diff --git a/addons/account_asset/views/account_asset_view.xml b/addons/account_asset/views/account_asset_view.xml
index 1062a574243..a9fc98331b9 100644
--- a/addons/account_asset/views/account_asset_view.xml
+++ b/addons/account_asset/views/account_asset_view.xml
@@ -99,10 +99,10 @@
<field name="state" widget="statusbar" statusbar_visible="draft,open"/>
</header>
<sheet>
- <div class="oe_button_box oe_right">
- <button class="oe_inline oe_stat_button" name="open_entries" type="object" icon="fa-pencil">
- <field string="Entries" name="entry_count" widget="statinfo" />
- </button>
+ <div class="oe_button_box" name="button_box">
+ <button class="oe_stat_button" name="open_entries" type="object" icon="fa-pencil">
+ <field string="Entries" name="entry_count" widget="statinfo" />
+ </button>
</div>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
diff --git a/addons/analytic/views/analytic_view.xml b/addons/analytic/views/analytic_view.xml
index 273b7373207..a86d5cbdb4f 100644
--- a/addons/analytic/views/analytic_view.xml
+++ b/addons/analytic/views/analytic_view.xml
@@ -8,8 +8,7 @@
<field name="arch" type="xml">
<form string="Analytic Account" version="7.0">
<sheet string="Analytic Account">
- <div class="oe_right oe_button_box" name="buttons">
- </div>
+ <div class="oe_button_box" name="button_box"/>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
diff --git a/addons/auth_signup/res_users_view.xml b/addons/auth_signup/res_users_view.xml
index 449ba7381fd..7c749271e77 100644
--- a/addons/auth_signup/res_users_view.xml
+++ b/addons/auth_signup/res_users_view.xml
@@ -24,7 +24,7 @@
</div>
</xpath>
<!-- add Reset Password button -->
- <xpath expr="//div[@class='oe_right oe_button_box']//button" position="replace">
+ <xpath expr="//div[@name='button_box']//button" position="replace">
<button string="Send Reset Password Instructions"
class="oe_link"
type="object" name="action_reset_password"
diff --git a/addons/base_setup/res_partner_view.xml b/addons/base_setup/res_partner_view.xml
index 15b80151831..3d48396ee7d 100644
--- a/addons/base_setup/res_partner_view.xml
+++ b/addons/base_setup/res_partner_view.xml
@@ -8,7 +8,7 @@
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.res_partner_kanban_view"/>
<field name="arch" type="xml">
- <xpath expr="//div[@class='oe_kanban_partner_categories']" position="inside">
+ <xpath expr="//div[contains(@class, 'oe_kanban_partner_categories')]" position="inside">
<span class="oe_kanban_list_many2many">
<field name="category_id"/>
</span>
diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml
index 42b20752a91..cfc52e0fdd4 100644
--- a/addons/crm/crm_lead_view.xml
+++ b/addons/crm/crm_lead_view.xml
@@ -121,8 +121,8 @@
on_change="onchange_stage_id(stage_id)"/>
</header>
<sheet>
- <div class="oe_right oe_button_box" name="buttons">
- <button class="oe_inline oe_stat_button" type="action"
+ <div class="oe_button_box" name="button_box">
+ <button class="oe_stat_button" type="action"
context="{'default_opportunity_id': active_id, 'search_default_opportunity_id': active_id, 'default_partner_id': partner_id, 'default_duration': 1.0}"
name="%(crm.crm_phonecall_category_phone_incoming0)d" icon="fa-phone">
<field string="Calls" name="calls_count" widget="statinfo"/>
@@ -284,7 +284,7 @@
</field>
</record>
- <!-- CRM Lead Kanban View -->
+ <!-- CRM Lead Kanban View -->
<record model="ir.ui.view" id="crm_case_kanban_view_leads">
<field name="name">CRM - Leads Kanban</field>
<field name="model">crm.lead</field>
@@ -300,15 +300,19 @@
<field name="message_summary"/>
<field name="message_unread"/>
<field name="tag_ids"/>
+ <field name="partner_id"/>
<templates>
<field name="date_deadline"/>
<t t-name="kanban-box">
- <div t-attf-class="oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_card oe_kanban_global_click">
- <div class="oe_dropdown_toggle oe_dropdown_kanban">
- <i class="fa fa-bars fa-lg"/>
- <ul class="oe_dropdown_menu">
- <t t-if="widget.view.is_action_enabled('edit')"><li><a type="edit">Edit Opportunity</a></li></t>
- <t t-if="widget.view.is_action_enabled('delete')"><li><a type="delete">Delete</a></li></t>
+ <div t-attf-class="#{kanban_color(record.color.raw_value)} o_kanban_small oe_kanban_global_click">
+ <div class="o_dropdown_kanban dropdown">
+
+ <a class="dropdown-toggle btn" data-toggle="dropdown" href="#" >
+ <span class="fa fa-bars fa-lg"/>
+ </a>
+ <ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
+ <t t-if="widget.editable"><li><a type="edit">Edit Opportunity</a></li></t>
+ <t t-if="widget.deletable"><li><a type="delete">Delete</a></li></t>
<li><a name="%(mail.action_email_compose_message_wizard)d" type="action" >Send Email</a></li>
<li><a type="action" name="%(crm.crm_phonecall_category_phone_incoming0)d">Calls</a></li>
<li><a name="action_schedule_meeting" type="object">Schedule Meeting</a></li>
@@ -317,32 +321,17 @@
</div>
<div class="oe_kanban_content">
<div>
- <strong><field name="name"/></strong>
- <t t-if="record.planned_revenue.raw_value">
- - <b><t t-esc="record.planned_revenue.value"/>
- <field name="company_currency"/></b>
- </t>
+ <field name="tag_ids"/>
</div>
<div>
- <field name="partner_id"/>
- </div>
- <div class="oe_deadline">
- <t t-if="record.date_deadline.raw_value and record.date_deadline.raw_value lt (new Date())" t-set="red">oe_kanban_text_red</t>
- <span t-attf-class="#{red || ''}"><field name="date_action"/></span>
- <t t-if="record.date_action.raw_value"> : </t>
- <field name="title_action"/>
- </div>
- <div class="oe_kanban_footer_left">
- <field name="tag_ids"/>
+ <strong><field name="name"/></strong>
</div>
- <div class="oe_kanban_bottom_left">
- <t t-raw="record.message_summary.raw_value"/>
+ <div class="text-muted">
+ <span t-if="record.planned_revenue.raw_value"><t t-esc="record.planned_revenue.value"/><field name="company_currency"/></span> <span t-if="record.partner_id.value"> - <t t-esc="record.partner_id.value"/></span>
</div>
- <div class="oe_kanban_bottom_right">
+ <div class="o_kanban_footer">
+ <field name="priority" widget="priority" groups="base.group_user"/> <t t-raw="record.message_summary.raw_value"/>
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value)" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar pull-right"/>
- <div class="pull-left" groups="base.group_user">
- <field name="priority" widget="priority"/>
- </div>
</div>
</div>
<div class="oe_clear"></div>
@@ -417,13 +406,13 @@
domain="['&amp;', ('team_ids', '=', team_id), '|', ('type', '=', type), ('type', '=', 'both')]"/>
</header>
<sheet>
- <div name="buttons" class="oe_right oe_button_box">
- <button class="oe_inline oe_stat_button" type="action"
+ <div class="oe_button_box" name="button_box">
+ <button class="oe_stat_button" type="action"
name="%(crm.crm_phonecall_category_phone_incoming0)d" icon="fa-phone"
context="{'default_opportunity_id': active_id, 'search_default_opportunity_id': active_id, 'default_partner_id': partner_id, 'default_duration': 1.0}">
<field string="Calls" name="calls_count" widget="statinfo"/>
</button>
- <button class="oe_inline oe_stat_button" type="object"
+ <button class="oe_stat_button" type="object"
context="{'partner_id': partner_id}"
name="action_schedule_meeting" icon="fa-calendar">
<field string="Meetings" name="meeting_count" widget="statinfo"/>
diff --git a/addons/crm/crm_phonecall_view.xml b/addons/crm/crm_phonecall_view.xml
index 7a68bab2d93..ac3a9493395 100644
--- a/addons/crm/crm_phonecall_view.xml
+++ b/addons/crm/crm_phonecall_view.xml
@@ -87,19 +87,28 @@
<field name="state" nolabel="1" widget="statusbar" clickable="True"/>
</header>
<sheet string="Phone Call">
- <div class="oe_right oe_button_box">
- <button class="oe_inline oe_stat_button" type="object" name="action_button_convert2opportunity"
+ <div class="oe_button_box" name="button_box">
+ <button class="oe_stat_button" type="object" name="action_button_convert2opportunity"
icon="fa-star" attrs="{'invisible':[ '|', ('opportunity_id','!=',False), ('state', 'not in', ('open', 'done'))]}"
help="Convert To Opportunity">
- <div>Convert To<br/>Opportunity</div>
+ <div class="o_form_field o_stat_info">
+ <span class="o_stat_text">Convert To</span>
+ <span class="o_stat_text">Opportunity</span>
+ </div>
</button>
- <button class="oe_inline oe_stat_button" type="action"
+ <button class="oe_stat_button" type="action"
name="%(phonecall_to_phonecall_act)d" icon="fa-phone">
- <div>Schedule<br/>Other Call</div>
+ <div class="o_form_field o_stat_info">
+ <span class="o_stat_text">Schedule</span>
+ <span class="o_stat_text">Other Call</span>
+ </div>
</button>
- <button class="oe_inline oe_stat_button" name="action_make_meeting" type="object" icon="fa-calendar fa-fw">
- <div>Schedule<br/>A Meeting</div>
+ <button class="oe_stat_button" name="action_make_meeting" type="object" icon="fa-calendar fa-fw">
+ <div class="o_form_field o_stat_info">
+ <span class="o_stat_text">Schedule</span>
+ <span class="o_stat_text">A Meeting</span>
+ </div>
</button>
</div>
<div class="oe_title">
diff --git a/addons/crm/res_partner_view.xml b/addons/crm/res_partner_view.xml
index 2049f729b99..07d50551378 100644
--- a/addons/crm/res_partner_view.xml
+++ b/addons/crm/res_partner_view.xml
@@ -68,12 +68,8 @@
<field name="meeting_count"/>
</field>
<xpath expr="//div[@class='oe_kanban_partner_links']" position="inside">
- <a name="%(relate_partner_opportunities)d" type="action" t-if="record.opportunity_count.value>0">
- <t t-esc="record.opportunity_count.value"/> Opportunities
- </a>
- <a name="%(calendar_event_partner)d" type="action" t-if="record.meeting_count.value>0">
- <t t-esc="record.meeting_count.value"/> Meetings
- </a>
+ <span class="badge" t-if="record.opportunity_count.value>0"><i class="fa fa-fw fa-star"/><t t-esc="record.opportunity_count.value"/></span>
+ <span class="badge" t-if="record.meeting_count.value>0"><i class="fa fa-fw fa-calendar"/><t t-esc="record.meeting_count.value"/></span>
</xpath>
</field>
</record>
@@ -89,31 +85,30 @@
<field name="user_id" position="after">
<field name="team_id" completion="1" groups="base.group_multi_salesteams"/>
</field>
- <xpath expr="//div[@name='buttons']" position="inside">
- <button class="oe_inline oe_stat_button o_res_partner_tip_opp" type="action"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button o_res_partner_tip_opp" type="action"
attrs="{'invisible': [('customer', '=', False)]}"
name="%(crm.crm_lead_opportunities)d"
icon="fa-star"
context="{'search_default_partner_id': active_id}">
<field string="Opportunities" name="opportunity_count" widget="statinfo"/>
</button>
- <button class="oe_inline oe_stat_button" type="object"
+ <button class="oe_stat_button" type="object"
name="schedule_meeting"
icon="fa-calendar"
context="{'partner_id': active_id}">
<field string="Meetings" name="meeting_count" widget="statinfo"/>
</button>
- <button class="oe_inline oe_stat_button" type="action"
+ <button class="oe_stat_button" type="action"
name="%(crm.crm_phonecall_category_phone_incoming0)d"
icon="fa-phone"
context="{'search_default_partner_id': active_id, 'default_duration': 1.0}">
<field string="Calls" name="phonecall_count" widget="statinfo"/>
</button>
- </xpath>
+ </div>
</data>
</field>
</record>
</data>
</openerp>
-
diff --git a/addons/crm_claim/res_partner_view.xml b/addons/crm_claim/res_partner_view.xml
index 11bf9e5a3ba..a2bcbf7a80f 100644
--- a/addons/crm_claim/res_partner_view.xml
+++ b/addons/crm_claim/res_partner_view.xml
@@ -8,14 +8,14 @@
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="priority" eval="50"/>
<field name="arch" type="xml">
- <xpath expr="//div[@name='buttons']" position="inside">
- <button class="oe_inline oe_stat_button" type="action"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" type="action"
context="{'search_default_partner_id': active_id, 'default_partner_id': active_id}"
name="%(crm_claim_category_claim0)d" icon="fa-comments" groups="base.group_sale_salesman">
<field string="Claims" name="claim_count" widget="statinfo"/>
</button>
- </xpath>
+ </div>
</field>
</record>
</data>
-</openerp>
+</openerp> \ No newline at end of file
diff --git a/addons/crm_project_issue/project_issue_view.xml b/addons/crm_project_issue/project_issue_view.xml
index 0b5dc781ba7..4552939fbb6 100644
--- a/addons/crm_project_issue/project_issue_view.xml
+++ b/addons/crm_project_issue/project_issue_view.xml
@@ -35,14 +35,17 @@
<field name="model">crm.lead</field>
<field name="inherit_id" ref="crm.crm_case_form_view_leads" />
<field name="arch" type="xml">
- <xpath expr="//div[@name='buttons']" position="inside">
- <button class="oe_inline oe_stat_button" type="action" name="%(convert_lead2projectissue_wizard_action)d" icon="fa-bug"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" type="action" name="%(convert_lead2projectissue_wizard_action)d" icon="fa-bug"
help="Convert to Issue">
- <div>Convert To<br/>Issue</div>
+ <div class="o_form_field o_stat_info">
+ <span class="o_stat_text">Convert To</span>
+ <span class="o_stat_text">Issue</span>
+ </div>
</button>
- </xpath>
+ </div>
</field>
</record>
</data>
-</openerp> \ No newline at end of file
+</openerp>
diff --git a/addons/event/event_view.xml b/addons/event/event_view.xml
index ea53ba9f9b0..11c0587c3ab 100644
--- a/addons/event/event_view.xml
+++ b/addons/event/event_view.xml
@@ -65,19 +65,19 @@
<field name="state" widget="statusbar" statusbar_visible="draft,confirm,done"/>
</header>
<sheet>
- <div class="oe_title">
- <label for="name" class="oe_edit_only"/>
- <h1><field name="name"/></h1>
- </div>
- <div class="oe_right oe_button_box" groups="base.group_user">
+ <div class="oe_button_box" name="button_box" groups="base.group_user">
<button name="%(event.act_event_registration_from_event)d"
type="action"
- class="oe_stat_button oe_inline oe_event_attendee_button"
+ class="oe_stat_button oe_event_attendee_button"
icon="fa-github"
help="Register with this event">
<field name="seats_reserved" widget="statinfo" string="Attendees"/>
</button>
</div>
+ <div class="oe_title">
+ <label for="name" class="oe_edit_only"/>
+ <h1><field name="name"/></h1>
+ </div>
<group name="main_field_group">
<group>
<field name="address_id" context="{'show_address': 1}" options='{"always_reload": True}'/>
@@ -165,7 +165,7 @@
<div class="oe_dropdown_toggle oe_dropdown_kanban">
<i class="fa fa-bars fa-lg"/>
<ul class="oe_dropdown_menu">
- <t t-if="widget.view.is_action_enabled('delete')">
+ <t t-if="widget.deletable">
<li><a type="delete">Delete</a></li>
</t>
<li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
diff --git a/addons/fleet/fleet_view.xml b/addons/fleet/fleet_view.xml
index 99825594dc8..296a46ae6e1 100644
--- a/addons/fleet/fleet_view.xml
+++ b/addons/fleet/fleet_view.xml
@@ -190,20 +190,7 @@
<field name="state_id" widget="statusbar" clickable="True" />
</header>
<sheet>
- <field name="image_medium" widget='image' class="oe_left oe_avatar"/>
- <div class="oe_title">
- <label for="model_id" class="oe_edit_only"/>
- <h1>
- <field name="model_id" class="oe_inline" on_change="on_change_model(model_id)"/>
- </h1>
- <label for="license_plate" class="oe_edit_only"/>
- <h2>
- <field name="license_plate" class="oe_inline"/>
- </h2>
- <label for="tag_ids" class="oe_edit_only"/>
- <field name="tag_ids" widget="many2many_tags" />
- </div>
- <div class="oe_right oe_button_box">
+ <div class="oe_button_box" name="button_box">
<button name="return_action_to_open"
type="object"
class="oe_stat_button"
@@ -245,6 +232,19 @@
<field name="odometer_count" widget="statinfo" string="Odometer"/>
</button>
</div>
+ <field name="image_medium" widget='image' class="oe_left oe_avatar"/>
+ <div class="oe_title">
+ <label for="model_id" class="oe_edit_only"/>
+ <h1>
+ <field name="model_id" class="oe_inline" on_change="on_change_model(model_id)"/>
+ </h1>
+ <label for="license_plate" class="oe_edit_only"/>
+ <h2>
+ <field name="license_plate" class="oe_inline"/>
+ </h2>
+ <label for="tag_ids" class="oe_edit_only"/>
+ <field name="tag_ids" widget="many2many_tags" />
+ </div>
<group col="2" string="General Properties">
<group >
<field name="driver_id" />
diff --git a/addons/gamification/views/badge.xml b/addons/gamification/views/badge.xml
index 386a1e19974..16a13e72960 100644
--- a/addons/gamification/views/badge.xml
+++ b/addons/gamification/views/badge.xml
@@ -42,8 +42,7 @@
<button string="Grant this Badge" type="action" name="%(action_grant_wizard)d" class="oe_highlight" attrs="{'invisible': [('remaining_sending','=',0)]}" />
</header>
<sheet>
- <div class="oe_right oe_button_box">
- </div>
+ <div class="oe_button_box" name="button_box"/>
<field name="image" widget='image' class="oe_left oe_avatar"/>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
diff --git a/addons/gamification/views/challenge.xml b/addons/gamification/views/challenge.xml
index c5f717f37a0..efd0c9f041c 100644
--- a/addons/gamification/views/challenge.xml
+++ b/addons/gamification/views/challenge.xml
@@ -40,6 +40,19 @@
<field name="state" widget="statusbar" clickable="True"/>
</header>
<sheet>
+ <!-- action buttons -->
+ <div class="oe_button_box" name="button_box">
+ <button type="action"
+ name="%(goals_from_challenge_act)d"
+ class="oe_stat_button"
+ icon="fa-gift"
+ attrs="{'invisible': [('state','=','draft')]}">
+ <div class="o_form_field o_stat_info">
+ <span class="o_stat_text">Related</span>
+ <span class="o_stat_text">Goals</span>
+ </div>
+ </button>
+ </div>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
@@ -53,16 +66,6 @@
</div>
</div>
- <!-- action buttons -->
- <div class="oe_right oe_button_box">
- <button type="action"
- name="%(goals_from_challenge_act)d"
- class="oe_stat_button"
- icon="fa-gift"
- attrs="{'invisible': [('state','=','draft')]}">
- <div>Related<br/>Goals</div>
- </button>
- </div>
<group>
<group>
<field name="period" attrs="{'readonly':[('state','!=','draft')]}"/>
diff --git a/addons/hr/hr_dashboard.xml b/addons/hr/hr_dashboard.xml
index 884e0cbc68c..9567eda3ed7 100644
--- a/addons/hr/hr_dashboard.xml
+++ b/addons/hr/hr_dashboard.xml
@@ -47,7 +47,7 @@
</div>
</div>
- <div t-if="widget.view.is_action_enabled('edit')" class="o_kanban_card_manage_settings row">
+ <div t-if="widget.editable" class="o_kanban_card_manage_settings row">
<div class="col-xs-8">
<li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
</div>
diff --git a/addons/hr/hr_view.xml b/addons/hr/hr_view.xml
index be7dfecdfdf..a57db47ccfb 100644
--- a/addons/hr/hr_view.xml
+++ b/addons/hr/hr_view.xml
@@ -23,6 +23,7 @@
<field name="arch" type="xml">
<form string="Employee">
<sheet>
+ <div class="oe_button_box" name="button_box"/>
<field name="image_medium" widget='image' class="oe_left oe_avatar"/>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
@@ -36,11 +37,8 @@
<label for="work_phone" class="oe_edit_only"/>
<field name="work_phone"/>
</div>
- <div class="oe_right oe_button_box" name="button_box">
- <!-- Put here related buttons -->
- </div>
<notebook>
- <page string="Public Information">
+ <page name="public" string="Public Information">
<group>
<group string="Contact Information">
<field name="address_id" on_change="onchange_address_id(address_id)"
@@ -141,14 +139,14 @@
</search>
</field>
</record>
- <!-- HR Kanban View -->
+ <!-- HR Kanban View -->
<record model="ir.ui.view" id="hr_kanban_view_employees">
<field name="name">HR - Employess Kanban</field>
<field name="model">hr.employee</field>
<field name="priority">10</field>
<field name="arch" type="xml">
- <kanban>
+ <kanban class="o_hr_employee_kanban">
<field name="last_login"/>
<field name="message_is_follower"/>
<field name="message_follower_ids"/>
@@ -157,40 +155,40 @@
<field name="message_unread"/>
<templates>
<t t-name="kanban-box">
- <div class="row oe_employee_details">
- <div class="col-md-4">
- <a type="open"><img t-att-src="kanban_image('hr.employee', 'image_medium', record.id.value)" class="img-responsive oe_employee_image"/></a>
+ <div class="o_kanban_two_column oe_kanban_global_click oe_employee_details">
+ <div class="o_kanban_image">
+ <img t-att-src="kanban_image('hr.employee', 'image_medium', record.id.value)"/>
+ <div class="o_employee_summary_icons">
+ <t t-raw="record.message_summary.raw_value"/>
+ <span title='Messages'><i class='fa fa-comments'/><t t-esc="record.message_ids.raw_value.length"/></span>
+ <span title='Followers'><i class='fa fa-users'/><t t-esc="record.message_follower_ids.raw_value.length"/></span>
</div>
- <div class="col-md-8">
- <h4>
- <a type="open"><field name="name"/><t t-if="record.login.raw_value"> (<field name="login"/>)</t></a>
- </h4>
- <ul>
- <li id="last_login">
- <span t-if="record.last_login.raw_value &amp;&amp; record.last_login.raw_value.is().today()" class="oe_kanban_button" style="font-size: 100%%">
- <t t-esc="moment(record.last_login.raw_value).format('LT')"/>
- </span>
- </li>
- <li t-if="record.job_id.raw_value"><field name="job_id"/></li>
- <li t-if="record.work_location.raw_value"><field name="work_location"/></li>
- <li t-if="record.work_phone.raw_value"><i class="fa fa-phone"></i> <field name="work_phone"/></li>
- <li t-if="record.mobile_phone.raw_value"><i class="fa fa-mobile"></i> <field name="mobile_phone"/></li>
- <li t-if="record.work_email.raw_value"><i class="fa fa-envelope"></i><a t-attf-href="mailto:#{record.work_email.value}"> <field name="work_email"/></a></li>
- </ul>
- <div class="oe_kanban_bottom_left">
- <t t-raw="record.message_summary.raw_value"/>
- <span title='Messages'><i class='fa fa-comments'/><t t-esc="record.message_ids.raw_value.length"/></span>
- <span title='Followers'><i class='fa fa-users'/><t t-esc="record.message_follower_ids.raw_value.length"/></span>
- </div>
- <div class="oe_followers" groups="base.group_user">
- <button t-if="record.message_is_follower.raw_value" name="action_unfollow" type="object" class="oe_follower oe_following">
- <span class="oe_unfollow">Unfollow</span>
- <span class="oe_following">Following</span>
- </button>
- <button t-if="! record.message_is_follower.raw_value" name="action_follow" type="object" class="oe_follower oe_notfollow">Follow</button>
- </div>
+ </div>
+ <div class="oe_kanban_details oe_employee_details_content">
+ <strong>
+ <field name="name"/><t t-if="record.login.raw_value"> (<field name="login"/>)</t>
+ </strong>
+ <ul>
+ <li id="last_login">
+ <span t-if="record.last_login.raw_value &amp;&amp; record.last_login.raw_value.is().today()" class="oe_kanban_button" style="font-size: 100%%">
+ <t t-esc="moment(record.last_login.raw_value).format('LT')"/>
+ </span>
+ </li>
+ <li t-if="record.job_id.raw_value"><field name="job_id"/></li>
+ <li t-if="record.work_location.raw_value"><field name="work_location"/></li>
+ <li t-if="record.work_email.raw_value"><i class="fa fa-envelope"></i> <field name="work_email"/></li>
+ <li t-if="record.work_phone.raw_value"><i class="fa fa-phone"></i> <field name="work_phone"/></li>
+ <li t-if="record.mobile_phone.raw_value"><i class="fa fa-mobile"></i> <field name="mobile_phone"/></li>
+ </ul>
+ <div class="oe_followers o_kanban_button">
+ <button t-if="record.message_is_follower.raw_value" name="action_unfollow" type="object" class="o_follow_btn o_following btn btn-primary">
+ <span class="o_unfollow">Unfollow</span>
+ <span class="o_following">Following</span>
+ </button>
+ <button t-if="!record.message_is_follower.raw_value" name="action_follow" type="object" class="o_follow_btn o_not_following btn btn-primary">Follow</button>
</div>
</div>
+ </div>
</t>
</templates>
</kanban>
@@ -352,14 +350,14 @@
<field name="state" widget="statusbar" statusbar_visible="recruit,open"/>
</header>
<sheet>
+ <div class="oe_right" name="button_box"/>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
- <h1><field name="name" class="oe_inline"/></h1>
+ <h1><field name="name"/></h1>
</div>
- <div class="oe_right" name="buttons"/>
<group name="employee_data">
- <field name="department_id" groups="hr.group_multi_departments" class="oe_inline"/>
- <field name="no_of_recruitment" class="oe_inline" />
+ <field name="department_id" groups="hr.group_multi_departments"/>
+ <field name="no_of_recruitment"/>
</group>
<div attrs="{'invisible': [('state', '!=', 'recruit')]}">
<label for="description"/>
@@ -520,4 +518,4 @@
groups="group_multi_departments"/>
</data>
-</openerp>
+</openerp> \ No newline at end of file
diff --git a/addons/hr/static/src/js/hr.js b/addons/hr/static/src/js/hr.js
deleted file mode 100644
index 9fda01cef95..00000000000
--- a/addons/hr/static/src/js/hr.js
+++ /dev/null
@@ -1,8 +0,0 @@
-odoo.define('hr.hr', function(require) {
-"use strict";
-
-var common = require('web_kanban.common');
-
-
-});
-
diff --git a/addons/hr/static/src/less/hr_dashboard.less b/addons/hr/static/src/less/hr_dashboard.less
index eada8b85395..e0dee9037ee 100644
--- a/addons/hr/static/src/less/hr_dashboard.less
+++ b/addons/hr/static/src/less/hr_dashboard.less
@@ -1,7 +1,11 @@
-.oe_kanban_view.o_kanban_dashboard.o_hr_kanban {
- .oe_kanban_record {
- max-width: 500px;
- min-width: 400px;
- min-height: 200px;
- }
+.o_kanban_view {
+ .o_kanban_record.oe_employee_details {
+ .oe_employee_details_content {
+ padding-left: 16px;
+
+ > h4 {
+ margin-top: 0;
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/addons/hr/views/hr.xml b/addons/hr/views/hr.xml
index 44fb6d8655e..e76ec3cc4ce 100644
--- a/addons/hr/views/hr.xml
+++ b/addons/hr/views/hr.xml
@@ -6,7 +6,6 @@
<link rel="stylesheet" href="/hr/static/src/css/hr.css"/>
<link rel="stylesheet" href="/hr/static/src/less/hr_dashboard.less"/>
<script type="text/javascript" src="/hr/static/src/js/suggestions.js"></script>
- <script type="text/javascript" src="/hr/static/src/js/hr.js"></script>
</xpath>
</template>
</data>
diff --git a/addons/hr_contract/hr_contract_view.xml b/addons/hr_contract/hr_contract_view.xml
index 59cf0d4e4c4..327d08fc68b 100644
--- a/addons/hr_contract/hr_contract_view.xml
+++ b/addons/hr_contract/hr_contract_view.xml
@@ -19,7 +19,7 @@
<field name="inherit_id" ref="hr.view_employee_form"/>
<field name="arch" type="xml">
<data>
- <xpath expr="//div[@name='button_box']" position="inside">
+ <div name="button_box" position="inside">
<button name="%(act_hr_employee_2_hr_contract)d"
class="oe_stat_button"
icon="fa-book"
@@ -27,7 +27,7 @@
groups="base.group_hr_manager">
<field name="contracts_count" widget="statinfo" string="Contracts"/>
</button>
- </xpath>
+ </div>
<xpath expr="//field[@name='coach_id']" position="after">
<field name="manager"/>
</xpath>
diff --git a/addons/hr_equipment/views/hr_equipment_views.xml b/addons/hr_equipment/views/hr_equipment_views.xml
index ef61997f586..2229b861651 100644
--- a/addons/hr_equipment/views/hr_equipment_views.xml
+++ b/addons/hr_equipment/views/hr_equipment_views.xml
@@ -92,8 +92,8 @@
<div class="oe_dropdown_toggle oe_dropdown_kanban">
<i class="fa fa-bars fa-lg" />
<ul class="oe_dropdown_menu">
- <t t-if="widget.view.is_action_enabled('edit')"><li><a type="edit">Edit...</a></li></t>
- <t t-if="widget.view.is_action_enabled('delete')"><li><a type="delete">Delete</a></li></t>
+ <t t-if="widget.editable"><li><a type="edit">Edit...</a></li></t>
+ <t t-if="widget.deletable"><li><a type="delete">Delete</a></li></t>
<li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
</ul>
</div>
@@ -192,13 +192,7 @@
<field name="arch" type="xml">
<form string="Equipments">
<sheet>
- <div class="oe_title">
- <label for="name" class="oe_edit_only" string="Name"/>
- <h1><field name="name" string="Name"/></h1>
- <label for="serial_no" class="oe_edit_only"/>
- <field name="serial_no"/>
- </div>
- <div class="oe_right oe_button_box" name="buttons">
+ <div class="oe_button_box" name="button_box">
<button name="%(hr_equipment_request_action_from_equipment)d"
type="action"
class="oe_stat_button"
@@ -206,6 +200,12 @@
<field string="Maintenance" name="maintenance_count" widget="statinfo"/>
</button>
</div>
+ <div class="oe_title">
+ <label for="name" class="oe_edit_only" string="Name"/>
+ <h1><field name="name" string="Name"/></h1>
+ <label for="serial_no" class="oe_edit_only"/>
+ <field name="serial_no"/>
+ </div>
<group>
<group>
<field name="category_id" groups="base.group_equipment_manager" on_change="1" options="{&quot;no_open&quot;: True}"/>
@@ -265,8 +265,8 @@
<div class="oe_dropdown_toggle oe_dropdown_kanban">
<i class="fa fa-bars fa-lg" />
<ul class="oe_dropdown_menu">
- <t t-if="widget.view.is_action_enabled('edit')"><li><a type="edit">Edit...</a></li></t>
- <t t-if="widget.view.is_action_enabled('delete')"><li><a type="delete">Delete</a></li></t>
+ <t t-if="widget.editable"><li><a type="edit">Edit...</a></li></t>
+ <t t-if="widget.deletable"><li><a type="delete">Delete</a></li></t>
<li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
</ul>
</div>
@@ -392,13 +392,7 @@
<field name="arch" type="xml">
<form string="Equipment Categories">
<sheet>
- <div class="oe_title">
- <label for="name" class="oe_edit_only" string="Category Name"/>
- <h1>
- <field name="name"/>
- </h1>
- </div>
- <div class="oe_right oe_button_box" name="buttons">
+ <div class="oe_button_box" name="button_box">
<button name="%(hr_equipment_action_from_category_form)d"
class="oe_stat_button"
icon="fa-laptop"
@@ -412,6 +406,12 @@
<field string="Maintenance" name="maintenance_count" widget="statinfo"/>
</button>
</div>
+ <div class="oe_title">
+ <label for="name" class="oe_edit_only" string="Category Name"/>
+ <h1>
+ <field name="name"/>
+ </h1>
+ </div>
<group>
<group col="4">
<field name="user_id"/>
diff --git a/addons/hr_evaluation/hr_evaluation_view.xml b/addons/hr_evaluation/hr_evaluation_view.xml
index 9cf0a3e37ab..b1337d3a027 100644
--- a/addons/hr_evaluation/hr_evaluation_view.xml
+++ b/addons/hr_evaluation/hr_evaluation_view.xml
@@ -147,14 +147,14 @@
<field name="evaluation_date"/>
</group>
</xpath>
- <xpath expr="//div[@name='button_box']" position="inside">
+ <div name="button_box" position="inside">
<button name="%(act_hr_employee_2_hr__evaluation_interview)d"
class="oe_stat_button"
icon="fa-sitemap"
type="action">
<field name="appraisal_count" widget="statinfo" string="Appraisals"/>
</button>
- </xpath>
+ </div>
</field>
</record>
@@ -284,7 +284,7 @@
<field name="state" widget="statusbar" statusbar_visible="waiting_answer,done"/>
</header>
<sheet>
- <div class="oe_right oe_button_box" name="button_box">
+ <div class="oe_button_box" name="button_box">
<button string="Send Reminder Email" name="%(mail.action_email_compose_message_wizard)d" type="action"
states="waiting_answer"
context="{'default_body': 'Hello,\n\nKindly post your response for the survey interview.\n\nThanks',
diff --git a/addons/hr_gamification/static/src/js/gamification.js b/addons/hr_gamification/static/src/js/gamification.js
index 765acb257e4..a7a0201900a 100644
--- a/addons/hr_gamification/static/src/js/gamification.js
+++ b/addons/hr_gamification/static/src/js/gamification.js
@@ -1,11 +1,11 @@
odoo.define('hr_gamification.hr_gamification', function(require) {
"use strict";
-var common = require('web_kanban.common');
+var KanbanRecord = require('web_kanban.Record');
-common.KanbanRecord.include({
+KanbanRecord.include({
on_card_clicked: function() {
- if (this.view.dataset.model === 'gamification.badge.user') {
+ if (this.model === 'gamification.badge.user') {
var action = {
type: 'ir.actions.act_window',
res_model: 'gamification.badge',
diff --git a/addons/hr_gamification/views/gamification.xml b/addons/hr_gamification/views/gamification.xml
index c3299a3c24b..3684cba5924 100644
--- a/addons/hr_gamification/views/gamification.xml
+++ b/addons/hr_gamification/views/gamification.xml
@@ -7,9 +7,9 @@
<field name="model">gamification.badge</field>
<field name="inherit_id" ref="gamification.badge_form_view"/>
<field name="arch" type="xml">
- <xpath expr="//div[@class='oe_right oe_button_box']" position="inside">
+ <div name="button_box" position="inside">
<button string="Granted Employees" type="object" name="get_granted_employees" attrs="{'invisible': [('stat_count','=',0)]}" />
- </xpath>
+ </div>
</field>
</record>
diff --git a/addons/hr_holidays/hr_holidays_view.xml b/addons/hr_holidays/hr_holidays_view.xml
index e98d4234033..164cefa9c97 100644
--- a/addons/hr_holidays/hr_holidays_view.xml
+++ b/addons/hr_holidays/hr_holidays_view.xml
@@ -589,7 +589,7 @@
</div>
</group>
</xpath>
- <xpath expr="//div[@name='button_box']" position="inside">
+ <div name="button_box" position="inside">
<button name="%(act_hr_employee_holiday_request_approved)d"
icon="fa-calendar"
class="oe_stat_button"
@@ -604,7 +604,7 @@
groups="base.group_hr_user">
<field name="leaves_count" widget="statinfo"/>
</button>
- </xpath>
+ </div>
</field>
</record>
diff --git a/addons/hr_payroll/hr_payroll_view.xml b/addons/hr_payroll/hr_payroll_view.xml
index 9114e4bd684..0874c6e61b1 100644
--- a/addons/hr_payroll/hr_payroll_view.xml
+++ b/addons/hr_payroll/hr_payroll_view.xml
@@ -221,7 +221,7 @@
<field name="state" widget="statusbar" statusbar_visible="draft,confirm"/>
</header>
<sheet>
- <div class="oe_right oe_button_box">
+ <div class="oe_button_box" name="button_box">
<button name="%(act_payslip_lines)d"
class="oe_stat_button"
icon="fa-money"
@@ -391,7 +391,7 @@
<field name="inherit_id" ref="hr.view_employee_form"/>
<field name="arch" type="xml">
<data>
- <xpath expr="//div[@name='button_box']" position="inside">
+ <div name="button_box" position="inside">
<button name="%(act_hr_employee_payslip_list)d"
class="oe_stat_button"
icon="fa-money"
@@ -399,7 +399,7 @@
groups="base.group_hr_user">
<field name="payslip_count" widget="statinfo" string="Payslips"/>
</button>
- </xpath>
+ </div>
</data>
</field>
</record>
diff --git a/addons/hr_recruitment/hr_recruitment_dashboard.xml b/addons/hr_recruitment/hr_recruitment_dashboard.xml
index 75d4a4564a1..e0965de2039 100644
--- a/addons/hr_recruitment/hr_recruitment_dashboard.xml
+++ b/addons/hr_recruitment/hr_recruitment_dashboard.xml
@@ -123,7 +123,7 @@
</div>
</div>
- <div t-if="widget.view.is_action_enabled('edit')" class="o_kanban_card_manage_settings row">
+ <div t-if="widget.editable" class="o_kanban_card_manage_settings row">
<div class="col-xs-8">
<li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
</div>
diff --git a/addons/hr_recruitment/hr_recruitment_view.xml b/addons/hr_recruitment/hr_recruitment_view.xml
index c3685c5f880..65c32f7eb3e 100644
--- a/addons/hr_recruitment/hr_recruitment_view.xml
+++ b/addons/hr_recruitment/hr_recruitment_view.xml
@@ -62,10 +62,12 @@
<field name="stage_id" widget="statusbar" clickable="True" options="{'fold_field': 'fold'}"/>
</header>
<sheet>
- <div class="oe_right oe_button_box">
+ <div class="oe_button_box" name="button_box">
<button name="action_makeMeeting" class="oe_stat_button" icon="fa-calendar" type="object"
help="Schedule interview with this applicant">
- <div>Meetings</div>
+ <div class="o_form_field o_stat_info">
+ <span class="o_stat_text">Meetings</span>
+ </div>
</button>
<button name="action_start_survey"
class="oe_stat_button"
@@ -74,7 +76,10 @@
help="Answer related job question"
context="{'survey_id': survey}"
attrs="{'invisible':[('survey','=',False)]}">
- <div>Start<br/>Interview</div>
+ <div class="o_form_field o_stat_info">
+ <span class="o_stat_text">Start</span>
+ <span class="o_stat_text">Interview</span>
+ </div>
</button>
<button name="action_print_survey"
class="oe_stat_button"
@@ -82,7 +87,10 @@
type="object"
help="Print interview report"
attrs="{'invisible':[('survey','=',False)]}">
- <div>Print<br/>Interview</div>
+ <div class="o_form_field o_stat_info">
+ <span class="o_stat_text">Print</span>
+ <span class="o_stat_text">Interview</span>
+ </div>
</button>
<button name="action_get_attachment_tree_view"
class="oe_stat_button"
@@ -268,7 +276,7 @@
<div class="oe_dropdown_toggle oe_dropdown_kanban">
<i class="fa fa-bars fa-lg"/>
<ul class="oe_dropdown_menu">
- <t t-if="widget.view.is_action_enabled('delete')"><li><a type="delete">Delete</a></li></t>
+ <t t-if="widget.deletable"><li><a type="delete">Delete</a></li></t>
<li><a name="action_makeMeeting" type="object">Schedule Interview</a></li>
<li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
</ul>
@@ -375,14 +383,11 @@
<field name="arch" type="xml">
<group name="employee_data" position="inside">
<label for="survey_id" groups="base.group_user"/>
- <div groups="base.group_user">
- <field name="survey_id" class="oe_inline"/>
- <button string="Print Interview" name="action_print_survey" type="object" attrs="{'invisible':[('survey_id','=',False)]}" class="oe_inline oe_link"/>
- </div>
- <label for="address_id"/>
- <div>
- <field name="address_id" context="{'show_address': 1}" domain= "[('is_company', '=', True )]"/>
+ <div groups="base.group_user" class="o_row">
+ <field name="survey_id"/>
+ <button string="Print Interview" name="action_print_survey" type="object" attrs="{'invisible':[('survey_id','=',False)]}" class="oe_link"/>
</div>
+ <field name="address_id" context="{'show_address': 1}" domain= "[('is_company', '=', True )]"/>
</group>
<group name="employee_data" position="after">
<notebook>
@@ -392,46 +397,45 @@
</notebook>
</group>
<xpath expr="//field[@name='department_id']" position="after">
- <label for="alias_name" string="Specific Email Address" attrs="{'invisible': [('alias_domain', '=', False)]}" help ="Define a specific contact address for this job position. If you keep it empty, the default email address will be used which is in human resources settings"/>
- <div name="alias_def" attrs="{'invisible': [('alias_domain', '=', False)]}">
- <field name="alias_id" class="oe_read_only oe_inline"
- string="Email Alias" required="0"/>
- <div class="oe_edit_only oe_inline" name="edit_alias" style="display: inline;" >
- <field name="alias_name" class="oe_inline"/>@<field name="alias_domain" class="oe_inline" readonly="1"/>
- </div>
+ <label for="alias_name" string="Specific Email Address" attrs="{'invisible': [('alias_domain', '=', False)]}" help="Define a specific contact address for this job position. If you keep it empty, the default email address will be used which is in human resources settings"/>
+ <div name="alias_def" attrs="{'invisible': [('alias_domain', '=', False)]}">
+ <field name="alias_id" class="oe_read_only" string="Email Alias" required="0"/>
+ <div class="oe_edit_only" name="edit_alias">
+ <field name="alias_name" class="oe_inline"/>@<field name="alias_domain" class="oe_inline" readonly="1"/>
</div>
+ </div>
</xpath>
<xpath expr="//field[@name='department_id']" position="after">
- <field name="user_id" class="oe_inline"/>
- </xpath>
- <xpath expr="//div[@name='buttons']" position="inside">
- <div class="oe_button_box" >
- <button class="oe_stat_button"
- icon="fa-file-o"
- name="%(action_hr_job_applications)d"
- context="{'default_user_id': user_id}"
- type="action">
- <field name="application_count" widget="statinfo" string="Applications"/>
- </button>
- <button class="oe_stat_button"
- icon="fa-users"
- name="%(action_hr_job_no_employee)d"
- type="action">
- <field name="no_of_employee" widget="statinfo" string="Employees"/>
- </button>
- <button class="oe_stat_button"
- icon="fa-book"
- name="action_get_attachment_tree_view"
- type="object">
- <field name="documents_count" widget="statinfo" string="Documents"/>
- </button>
- <button class="oe_stat_button" type="action"
- name="%(action_hr_job_sources)d" icon="fa-share"
- context="{'default_job_id': active_id}">
- <div>Trackers</div>
- </button>
- </div>
+ <field name="user_id"/>
</xpath>
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button"
+ icon="fa-file-o"
+ name="%(action_hr_job_applications)d"
+ context="{'default_user_id': user_id}"
+ type="action">
+ <field name="application_count" widget="statinfo" string="Applications"/>
+ </button>
+ <button class="oe_stat_button"
+ icon="fa-users"
+ name="%(action_hr_job_no_employee)d"
+ type="action">
+ <field name="no_of_employee" widget="statinfo" string="Employees"/>
+ </button>
+ <button class="oe_stat_button"
+ icon="fa-book"
+ name="action_get_attachment_tree_view"
+ type="object">
+ <field name="documents_count" widget="statinfo" string="Documents"/>
+ </button>
+ <button class="oe_stat_button" type="action"
+ name="%(action_hr_job_sources)d" icon="fa-share"
+ context="{'default_job_id': active_id}">
+ <div class="o_form_field o_stat_info">
+ <span class="o_stat_text">Trackers</span>
+ </div>
+ </button>
+ </div>
</field>
</record>
@@ -502,6 +506,7 @@
<menuitem
name="Recruitment"
id="menu_hr_recruitment_root"
+ web_icon="hr_recruitment,static/description/icon.png"
sequence="80"/>
<menuitem id="menu_hr_recruitment_configuration" name="Configuration" parent="menu_hr_recruitment_root"
@@ -695,4 +700,4 @@
</record>
</data>
-</openerp>
+</openerp> \ No newline at end of file
diff --git a/addons/hr_recruitment/static/src/js/job_position.js b/addons/hr_recruitment/static/src/js/job_position.js
index 9361c66cf7d..214f161ad99 100644
--- a/addons/hr_recruitment/static/src/js/job_position.js
+++ b/addons/hr_recruitment/static/src/js/job_position.js
@@ -1,11 +1,11 @@
odoo.define('hr_recruitment.hr_recruitment', function(require) {
"use strict";
-var common = require('web_kanban.common');
+var KanbanRecord = require('web_kanban.Record');
-common.KanbanRecord.include({
+KanbanRecord.include({
on_card_clicked: function() {
- if (this.view.dataset.model === 'hr.job') {
+ if (this.model === 'hr.job') {
this.$('.oe_applications a').first().click();
} else {
this._super.apply(this, arguments);
diff --git a/addons/hr_timesheet/hr_timesheet_view.xml b/addons/hr_timesheet/hr_timesheet_view.xml
index 78636517250..b6026b8ae0e 100644
--- a/addons/hr_timesheet/hr_timesheet_view.xml
+++ b/addons/hr_timesheet/hr_timesheet_view.xml
@@ -118,10 +118,10 @@
<field name="invoice_on_timesheets"/>
<label for="invoice_on_timesheets"/>
</xpath>
- <xpath expr='//div[@name="buttons"]' position='inside'>
- <button class="oe_inline oe_stat_button" type="action" name="%(act_analytic_cost_revenue)d"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" type="action" name="%(act_analytic_cost_revenue)d"
icon="fa-usd" string="Cost/Revenue" widget="statinfo"/>
- </xpath>
+ </div>
</field>
</record>
diff --git a/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml b/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml
index 29f79da1529..1ff77c6fe1c 100644
--- a/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml
+++ b/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml
@@ -87,12 +87,15 @@
<field name="state" widget="statusbar" statusbar_visible="new,confirm,done"/>
</header>
<sheet>
- <div class="oe_right oe_button_box" name="buttons">
+ <div class="oe_button_box" name="button_box">
<button type="action"
name="%(act_hr_timesheet_sheet_sheet_2_hr_analytic_timesheet)d"
class="oe_stat_button"
icon="fa-clock-o">
- <div><strong><field name="total_timesheet" widget="float_time"/></strong><br/>Timesheet</div>
+ <div class="o_form_field o_stat_info">
+ <span class="o_stat_value"><field name="total_timesheet" widget="float_time"/></span>
+ <span class="o_stat_text">Timesheet</span>
+ </div>
</button>
<button type="action" groups="base.group_hr_attendance"
class="oe_stat_button" icon="fa-users"
@@ -378,7 +381,7 @@
<field name="model">hr.employee</field>
<field name="inherit_id" ref="hr_timesheet.hr_timesheet_employee_extd_form"/>
<field name="arch" type="xml">
- <xpath expr="//div[@name='button_box']" position="inside">
+ <div name="button_box" position="inside">
<button name="%(act_hr_employee_2_hr_timesheet)d"
type="action"
class="oe_stat_button"
@@ -386,7 +389,7 @@
groups="base.group_hr_manager">
<field name="timesheet_count" widget="statinfo" string="Timesheets"/>
</button>
- </xpath>
+ </div>
</field>
</record>
diff --git a/addons/im_livechat/views/im_livechat_channel_views.xml b/addons/im_livechat/views/im_livechat_channel_views.xml
index f4be00b331c..34d5bb66696 100644
--- a/addons/im_livechat/views/im_livechat_channel_views.xml
+++ b/addons/im_livechat/views/im_livechat_channel_views.xml
@@ -71,6 +71,14 @@
<field name="arch" type="xml">
<form>
<sheet>
+ <div class="oe_button_box" name="button_box">
+ <button class="oe_stat_button" type="action" attrs="{'invisible':[('nbr_session','=', 0)]}" name="%(im_chat_session_action_from_channel)d" icon="fa-comments">
+ <field string="Sessions" name="nbr_session" widget="statinfo"/>
+ </button>
+ <button name="action_view_rating" attrs="{'invisible':[('rating_percentage_satisfaction','=', -1)]}" class="oe_stat_button" type="object" icon="fa-smile-o">
+ <field string="% Happy" name="rating_percentage_satisfaction" widget="statinfo"/>
+ </button>
+ </div>
<field name="image" widget='image' class="oe_avatar oe_left" options='{"preview_image": "image_medium"}'/>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
@@ -83,14 +91,6 @@
<field name="are_you_inside" invisible="1"/>
</div>
</div>
- <div class="oe_right oe_button_box" name="buttons">
- <button class="oe_inline oe_stat_button" type="action" attrs="{'invisible':[('nbr_session','=', 0)]}" name="%(im_chat_session_action_from_channel)d" icon="fa-comments">
- <field string="Sessions" name="nbr_session" widget="statinfo"/>
- </button>
- <button name="action_view_rating" attrs="{'invisible':[('rating_percentage_satisfaction','=', -1)]}" class="oe_stat_button" type="object" icon="fa-smile-o">
- <field string="% Happy" name="rating_percentage_satisfaction" widget="statinfo"/>
- </button>
- </div>
<group>
<group string="Operators">
<field name="user_ids" widget="many2many_kanban" nolabel="1" colspan="2">
diff --git a/addons/mail/views/mail_alias_views.xml b/addons/mail/views/mail_alias_views.xml
index c4d1e67dd37..f399e51a7b4 100644
--- a/addons/mail/views/mail_alias_views.xml
+++ b/addons/mail/views/mail_alias_views.xml
@@ -9,8 +9,7 @@
<field name="arch" type="xml">
<form string="Alias">
<sheet>
- <h2><field name="alias_name" class="oe_inline"/>@<field name="alias_domain" class="oe_inline"/></h2>
- <div class="oe_right oe_button_box">
+ <div class="oe_button_box" name="button_box">
<button name="open_document" string="Open Document"
type="object" class="oe_link"
attrs="{'invisible': ['|', ('alias_model_id', '=', False), ('alias_force_thread_id', '=', 0)]}"/>
@@ -18,6 +17,7 @@
type="object" class="oe_link"
attrs="{'invisible': ['|', ('alias_parent_model_id', '=', False), ('alias_parent_thread_id', '=', 0)]}"/>
</div>
+ <h2><field name="alias_name" class="oe_inline"/>@<field name="alias_domain" class="oe_inline"/></h2>
<group>
<field name="alias_model_id"/>
<field name="alias_force_thread_id"/>
diff --git a/addons/mail/views/mail_template_views.xml b/addons/mail/views/mail_template_views.xml
index 5ba30950ef0..a1d4d2dc1bf 100644
--- a/addons/mail/views/mail_template_views.xml
+++ b/addons/mail/views/mail_template_views.xml
@@ -7,30 +7,36 @@
<field name="arch" type="xml">
<form string="Templates">
<sheet>
- <div class="oe_title">
- <label for="name" class="oe_edit_only"/><h1><field name="name" required="1"/></h1>
- <group>
- <field name="model_id" required="1" options="{'no_create': True}"/>
- <field name="model" invisible="1"/>
- </group>
- </div>
- <div class="oe_right oe_button_box" name="buttons">
+ <div class="oe_button_box" name="button_box">
<field name="ref_ir_act_window" invisible="1"/>
- <button class="oe_inline oe_stat_button" name="create_action" type="object"
+ <button class="oe_stat_button" name="create_action" type="object"
attrs="{'invisible':[('ref_ir_act_window','!=',False)]}" icon="fa-plus"
help="Display an option on related documents to open a composition wizard with this template">
- <div>Add<br/>Context Action</div>
+ <div class="o_form_field o_stat_info">
+ <span class="o_stat_text">Add</span>
+ <span class="o_stat_text">Context Action</span>
+ </div>
</button>
<button name="unlink_action" type="object"
class="oe_stat_button" icon="fa-minus"
attrs="{'invisible':[('ref_ir_act_window','=',False)]}"
help="Remove the contextual action to use this template on related documents" widget="statinfo">
- <div>Remove<br/>Context Action</div>
+ <div class="o_form_field o_stat_info">
+ <span class="o_stat_text">Remove</span>
+ <span class="o_stat_text">Context Action</span>
+ </div>
</button>
- <button class="oe_inline oe_stat_button" name="%(wizard_email_template_preview)d" icon="fa-search-plus" string="Preview"
+ <button class="oe_stat_button" name="%(wizard_email_template_preview)d" icon="fa-search-plus" string="Preview"
type="action" target="new"
context="{'template_id':active_id}"/>
</div>
+ <div class="oe_title">
+ <label for="name" class="oe_edit_only"/><h1><field name="name" required="1"/></h1>
+ <group>
+ <field name="model_id" required="1" options="{'no_create': True}"/>
+ <field name="model" invisible="1"/>
+ </group>
+ </div>
<notebook>
<page string="Content">
<label for="subject"/>
diff --git a/addons/marketing_campaign/marketing_campaign_view.xml b/addons/marketing_campaign/marketing_campaign_view.xml
index 9442f30a219..de7359c8740 100644
--- a/addons/marketing_campaign/marketing_campaign_view.xml
+++ b/addons/marketing_campaign/marketing_campaign_view.xml
@@ -61,13 +61,16 @@
<field name="state" readonly="1" widget="statusbar" statusbar_visible="draft,running,done"/>
</header>
<sheet string="Campaign">
- <div class="oe_right oe_button_box" name="button_box">
+ <div class="oe_button_box" name="button_box">
<button type="action"
name="%(act_marketing_campaing_stat)d"
class="oe_stat_button"
icon="fa-keyboard-o"
help="Marketing Campaign Statistics">
- <div>Campaign<br/>Statistics</div>
+ <div class="o_form_field o_stat_info">
+ <span class="o_stat_text">Campaign</span>
+ <span class="o_stat_text">Statistics</span>
+ </div>
</button>
<button type="action"
name="%(act_marketing_campaing_segment_opened)d"
diff --git a/addons/mass_mailing/static/src/js/mass_mailing.js b/addons/mass_mailing/static/src/js/mass_mailing.js
index b43a138f2c2..3785cf87070 100644
--- a/addons/mass_mailing/static/src/js/mass_mailing.js
+++ b/addons/mass_mailing/static/src/js/mass_mailing.js
@@ -1,14 +1,14 @@
odoo.define('mass_mailing.mass_mailing', function (require) {
var core = require('web.core');
-var common = require('web_kanban.common');
+var KanbanRecord = require('web_kanban.Record');
var KanbanView = require('web_kanban.KanbanView');
var _t = core._t;
-common.KanbanRecord.include({
+KanbanRecord.include({
on_card_clicked: function (event) {
- if (this.view.dataset.model === 'mail.mass_mailing.campaign') {
+ if (this.model === 'mail.mass_mailing.campaign') {
this.$('.oe_mailings').click();
} else {
this._super.apply(this, arguments);
diff --git a/addons/mass_mailing/views/email_template.xml b/addons/mass_mailing/views/email_template.xml
index 73fb508b44b..c2526fe3678 100644
--- a/addons/mass_mailing/views/email_template.xml
+++ b/addons/mass_mailing/views/email_template.xml
@@ -10,6 +10,12 @@
<field name="arch" type="xml">
<form string="Templates">
<sheet>
+ <div class="oe_button_box" name="button_box">
+ <button name="%(mail.wizard_email_template_preview)d" string="Preview"
+ type="action" target="new"
+ context="{'template_id':active_id}"/>
+ <br />
+ </div>
<group>
<group>
<field name="name" required="True"/>
@@ -19,14 +25,6 @@
<field name="model" invisible="True"/>
<field name="use_default_to" invisible="1"/>
</group>
- <group>
- <div class="oe_right oe_button_box" name="buttons">
- <button name="%(mail.wizard_email_template_preview)d" string="Preview"
- type="action" target="new"
- context="{'template_id':active_id}"/>
- <br />
- </div>
- </group>
</group>
<notebook>
<page string="Body">
@@ -50,11 +48,11 @@
<div t-attf-class="oe_kanban_card oe_kanban_global_click oe_kanban_email_template">
<div class="oe_dropdown_toggle oe_dropdown_kanban">
<i class="fa fa-bars fa-lg"/>
- <ul class="oe_dropdown_menu" t-if="widget.view.is_action_enabled('edit') or widget.view.is_action_enabled('delete')">
- <t t-if="widget.view.is_action_enabled('edit')">
+ <ul class="oe_dropdown_menu" t-if="widget.editable or widget.deletable">
+ <t t-if="widget.editable">
<li><a type="edit">Edit</a></li>
</t>
- <t t-if="widget.view.is_action_enabled('delete')">
+ <t t-if="widget.deletable">
<li><a type="delete">Delete</a></li>
</t>
</ul>
diff --git a/addons/mass_mailing/views/mass_mailing.xml b/addons/mass_mailing/views/mass_mailing.xml
index 6b73230ca18..baebe825304 100644
--- a/addons/mass_mailing/views/mass_mailing.xml
+++ b/addons/mass_mailing/views/mass_mailing.xml
@@ -245,9 +245,9 @@
<field name="arch" type="xml">
<form string="Contact List">
<sheet>
- <div class="oe_right oe_button_box" name="buttons">
+ <div class="oe_button_box" name="button_box">
<button name="%(mass_mailing.action_view_mass_mailing_contacts_from_list)d"
- type="action" icon="fa-user" class="oe_stat_button pull-right">
+ type="action" icon="fa-user" class="oe_stat_button">
<field name="contact_nbr" string="Recipients" widget="statinfo"/>
</button>
</div>
@@ -392,7 +392,7 @@
</strong></p>
</div>
<sheet>
- <div class="oe_button_box pull-right" attrs="{'invisible': [('state', 'in', ('draft','test'))]}">
+ <div class="oe_button_box" name="button_box" attrs="{'invisible': [('state', 'in', ('draft','test'))]}">
<button name="%(action_view_mail_mail_statistics_mailing)d" type="action"
icon="fa-envelope-o" class="oe_stat_button"
attrs="{'invisible': [('sent', '=', 0)]}" >
@@ -499,7 +499,7 @@
<div class="oe_dropdown_toggle oe_dropdown_kanban">
<i class="fa fa-bars fa-lg"/>
<ul class="oe_dropdown_menu">
- <t t-if="widget.view.is_action_enabled('delete')">
+ <t t-if="widget.deletable">
<li><a type="delete">Delete</a></li>
</t>
</ul>
@@ -705,43 +705,39 @@
<span><field name="stage_id" widget="statusbar" clickable="True"/></span>
</header>
<sheet>
+ <field name="total" invisible="1"/>
+ <div class="oe_button_box" name="button_box"
+ attrs="{'invisible': [('total', '=', 0)]}">
+ <button name="%(action_view_mass_mailings_from_campaign)d"
+ type="action" class="oe_stat_button" icon="fa-envelope-o">
+ <field name="total_mailings" widget="statinfo" string="Mailings"/>
+ </button>
+ <button name="%(action_view_mail_mail_statistics_mailing)d" type="action"
+ icon="fa-envelope-o" class="oe_stat_button"
+ attrs="{'invisible': [('sent', '=', 0)]}" >
+ <field name="sent" string="Emails Sent" widget="statinfo"/>
+ </button>
+ <button name="%(action_view_mass_mailing_contacts)d"
+ type="action" class="oe_stat_button">
+ <field name="received_ratio" widget="percentpie" string="Received"/>
+ </button>
+ <button name="%(action_view_mass_mailing_contacts)d"
+ type="action" class="oe_stat_button">
+ <field name="opened_ratio" widget="percentpie" string="Opened"/>
+ </button>
+ <button name="%(action_view_mass_mailing_contacts)d"
+ type="action" class="oe_stat_button">
+ <field name="replied_ratio" widget="percentpie" string="Replied"/>
+ </button>
+ <button name="%(dropdb snipp)d"
+ type="action" class="oe_stat_button">
+ <field name="clicks_ratio" widget="percentpie" string="Clicks"/>
+ </button>
+ </div>
<group>
- <group>
- <field name="name" string="Campaign Name" on_change="on_change_campaign_name(name)"/>
- <field name="user_id"/>
- <field name="tag_ids" widget="many2many_tags"/>
- </group>
- <group>
- <field name="total" invisible="1"/>
- <div class="oe_right oe_button_box" name="buttons"
- attrs="{'invisible': [('total', '=', 0)]}">
- <button name="%(action_view_mass_mailings_from_campaign)d"
- type="action" class="oe_inline oe_stat_button" icon="fa-envelope-o">
- <field name="total_mailings" widget="statinfo" string="Mailings"/>
- </button>
- <button name="%(action_view_mail_mail_statistics_mailing)d" type="action"
- icon="fa-envelope-o" class="oe_stat_button"
- attrs="{'invisible': [('sent', '=', 0)]}" >
- <field name="sent" string="Emails Sent" widget="statinfo"/>
- </button>
- <button name="%(action_view_mass_mailing_contacts)d"
- type="action" class="oe_stat_button oe_inline">
- <field name="received_ratio" widget="percentpie" string="Received"/>
- </button>
- <button name="%(action_view_mass_mailing_contacts)d"
- type="action" class="oe_stat_button oe_inline">
- <field name="opened_ratio" widget="percentpie" string="Opened"/>
- </button>
- <button name="%(action_view_mass_mailing_contacts)d"
- type="action" class="oe_stat_button oe_inline">
- <field name="replied_ratio" widget="percentpie" string="Replied"/>
- </button>
- <button name="%(dropdb snipp)d"
- type="action" class="oe_stat_button">
- <field name="clicks_ratio" widget="percentpie" string="Clicks"/>
- </button>
- </div>
- </group>
+ <field name="name" string="Campaign Name" on_change="on_change_campaign_name(name)"/>
+ <field name="user_id"/>
+ <field name="tag_ids" widget="many2many_tags"/>
</group>
<notebook>
<page string="Tracking">
@@ -787,10 +783,10 @@
<div class="oe_dropdown_toggle oe_dropdown_kanban">
<i class="fa fa-bars fa-lg"/>
<ul class="oe_dropdown_menu">
- <t t-if="widget.view.is_action_enabled('edit')">
+ <t t-if="widget.editable">
<li><a type="edit">Settings</a></li>
</t>
- <t t-if="widget.view.is_action_enabled('delete')">
+ <t t-if="widget.deletable">
<li><a type="delete">Delete</a></li>
</t>
<li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
diff --git a/addons/mrp/mrp_view.xml b/addons/mrp/mrp_view.xml
index 1913fe3e3ce..32c042f1604 100644
--- a/addons/mrp/mrp_view.xml
+++ b/addons/mrp/mrp_view.xml
@@ -1105,12 +1105,12 @@
<field name="inherit_id" ref="product.product_template_only_form_view"/>
<field name="groups_id" eval="[(4, ref('mrp.group_mrp_user'))]"/>
<field name="arch" type="xml">
- <div name="buttons" position="inside">
- <button class="oe_inline oe_stat_button" name="%(template_open_bom)d" type="action"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" name="%(template_open_bom)d" type="action"
attrs="{'invisible':[('type', '=', 'service')]}" icon="fa-flask">
<field string="Bill of Materials" name="bom_count" widget="statinfo" />
</button>
- <button class="oe_inline oe_stat_button" name="action_view_mos" type="object"
+ <button class="oe_stat_button" name="action_view_mos" type="object"
attrs="{'invisible':[('type', '=', 'service')]}" icon="fa-list-alt">
<field string="Manufacturing" name="mo_count" widget="statinfo" />
</button>
@@ -1124,12 +1124,12 @@
<field name="inherit_id" ref="product.product_normal_form_view"/>
<field name="groups_id" eval="[(4, ref('mrp.group_mrp_user'))]"/>
<field name="arch" type="xml">
- <div name="buttons" position="inside">
- <button class="oe_inline oe_stat_button" name="action_view_bom" type="object"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" name="action_view_bom" type="object"
attrs="{'invisible':[('type', '=', 'service')]}" icon="fa-flask">
<field string="Bill of Materials" name="bom_count" widget="statinfo" />
</button>
- <button class="oe_inline oe_stat_button" name="%(act_product_mrp_production)d" type="action"
+ <button class="oe_stat_button" name="%(act_product_mrp_production)d" type="action"
attrs="{'invisible':[('type', '=', 'service')]}" icon="fa-list-alt">
<field string="Manufacturing" name="mo_count" widget="statinfo" />
</button>
diff --git a/addons/note/note_view.xml b/addons/note/note_view.xml
index 06f313730be..dc49df48bb3 100644
--- a/addons/note/note_view.xml
+++ b/addons/note/note_view.xml
@@ -54,32 +54,32 @@
<templates>
<t t-name="kanban-box">
- <div t-attf-class="oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_global_click_edit oe_semantic_html_override oe_kanban_card">
- <div class="oe_dropdown_kanban oe_dropdown_toggle">
- <!-- dropdown menu -->
- <i class="fa fa-bars fa-lg"/>
- <ul class="oe_dropdown_menu">
- <li><a type="delete">Delete</a></li>
- <li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
- </ul>
+ <div t-attf-class="#{kanban_color(record.color.raw_value)} oe_kanban_global_click_edit oe_semantic_html_override oe_kanban_card">
+
+ <div class="o_dropdown_kanban dropdown">
+ <a class="dropdown-toggle btn" data-toggle="dropdown" href="#" >
+ <span class="fa fa-bars fa-lg"/>
+ </a>
+ <ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
+ <li><a type="delete">Delete</a></li>
+ <li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
+ </ul>
</div>
- <div style="display: inline" class="oe_dropdown_kanban">
+ <span class="oe_dropdown_kanban">
<a name="onclick_note_is_done" type="object" t-if="record.open.raw_value"><i class="fa fa-check"/></a>
<a name="onclick_note_not_done" type="object" t-if="!record.open.raw_value"><i class="fa fa-check"/></a>
- </div>
+ </span>
<!-- kanban note -->
- <div t-attf-class="oe_kanban_content #{record.open.raw_value ? '' : 'note_text_line_through'}">
+ <span t-attf-class="oe_kanban_content #{record.open.raw_value ? '' : 'note_text_line_through'}">
<!-- title -->
<field name="name"/>
- </div>
- <div class="oe_clear"></div>
+ </span>
+ <div class="clearfix"></div>
<field name="tag_ids"/>
- <div class="oe_right">
<t t-foreach="record.message_follower_ids.raw_value" t-as="follower">
- <img t-att-src="kanban_image('res.partner', 'image_small', follower)" width="24" height="24" class="oe_kanban_avatar" t-att-data-member_id="follower"/>
+ <img t-att-src="kanban_image('res.partner', 'image_small', follower)" width="24" height="24" class="oe_kanban_avatar pull-right" t-att-data-member_id="follower"/>
</t>
- </div>
- <div class="oe_clear"></div>
+ <div class="clearfix"></div>
</div>
</t>
</templates>
@@ -106,12 +106,14 @@
<field name="name">note.note.form</field>
<field name="model">note.note</field>
<field name="arch" type="xml">
- <form string="Note" class="oe_form_nomargin">
+ <form string="Note" class="oe_form_nomargin o_note_form_view">
<header>
- <field name="tag_ids" widget="many2many_tags" class="oe_inline" placeholder="Tags"/>
+ <field name="tag_ids" widget="many2many_tags" placeholder="Tags"/>
<field name="stage_id" domain="[('user_id','=',uid)]" widget="statusbar" clickable="1"/>
</header>
- <field name="memo" widget="html" class="oe_memo" editor_height="450px" />
+ <sheet>
+ <field name="memo" widget="html" class="oe_memo" editor_height="450px" />
+ </sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" widget="mail_thread"/>
@@ -182,9 +184,9 @@
</field>
</record>
- <menuitem name="Notes" id="menu_note_notes" sequence="3" action="note.action_note_note"/>
+ <menuitem name="Notes" id="menu_note_notes" sequence="3" action="note.action_note_note" web_icon="note,static/description/icon.png"/>
<menuitem name="Configuration" id="menu_note_configuration" sequence="100" parent="menu_note_notes" groups="base.group_configuration"/>
<menuitem name="Stages" id="menu_notes_stage" parent="menu_note_configuration" action="note.action_note_stage" sequence="21" />
</data>
-</openerp>
+</openerp> \ No newline at end of file
diff --git a/addons/point_of_sale/point_of_sale_view.xml b/addons/point_of_sale/point_of_sale_view.xml
index 5af35bf7092..aeca4224ae7 100644
--- a/addons/point_of_sale/point_of_sale_view.xml
+++ b/addons/point_of_sale/point_of_sale_view.xml
@@ -806,14 +806,20 @@
</header>
<sheet>
- <div class="oe_right oe_button_box">
+ <div class="oe_button_box" name="button_box">
<button class="oe_stat_button" name="%(action_pos_box_in)d"
type="action" states="opened,closing_control" icon="fa-level-down">
- <div>Put<br/>Money In</div>
+ <div class="o_form_field o_stat_info">
+ <span class="o_stat_text">Put</span>
+ <span class="o_stat_text">Money In</span>
+ </div>
</button>
<button class="oe_stat_button" name="%(action_pos_box_out)d"
type="action" states="opened,closing_control" icon="fa-level-up">
- <div>Take<br/>Money Out</div>
+ <div class="o_form_field o_stat_info">
+ <span class="o_stat_text">Take</span>
+ <span class="o_stat_text">Money Out</span>
+ </div>
</button>
</div>
<h1 class="oe_title">
diff --git a/addons/procurement/procurement_view.xml b/addons/procurement/procurement_view.xml
index 5c3aad1c21e..6a28fbd58f7 100644
--- a/addons/procurement/procurement_view.xml
+++ b/addons/procurement/procurement_view.xml
@@ -34,9 +34,9 @@
<field name="state" readonly="1" widget="statusbar" statusbar_visible="draft,confirmed,running,done" />
</header>
<sheet>
- <div class="oe_right oe_button_box" name="button_box">
- <button name="do_view_procurements" class="oe_stat_button" icon="fa-bars" string="Group's Procurements" type="object"/>
- </div>
+ <div class="oe_button_box" name="button_box">
+ <button name="do_view_procurements" class="oe_stat_button" icon="fa-bars" string="Group's Procurements" type="object"/>
+ </div>
<group>
<group>
<field name="product_id" on_change="onchange_product_id(product_id)"/>
@@ -98,7 +98,7 @@
<field name="arch" type="xml">
<form string="Procurement group">
<sheet>
- <div class="oe_right oe_button_box" name="button_box">
+ <div class="oe_button_box" name="button_box">
<button name="%(do_view_procurements)d" string="Procurements" type="action"/>
</div>
<group>
diff --git a/addons/product/product_view.xml b/addons/product/product_view.xml
index 4a245ed2e50..2a97f0d262a 100644
--- a/addons/product/product_view.xml
+++ b/addons/product/product_view.xml
@@ -19,7 +19,7 @@
<field string="Product Variant" name="product_variant_ids" filter_domain="['|', ('product_variant_ids.name','ilike',self), ('product_variant_ids.attribute_value_ids.attribute_id.name','ilike',self)]"/>
<field name="company_id"/>
<field name="pricelist_id" widget="selection" context="{'pricelist': self}" filter_domain="[]" groups="product.group_sale_pricelist"/> <!-- Keep widget=selection on this field to pass numeric `self` value, which is not the case for regular m2o widgets! -->
- <group expand='0' string='Group by...'>
+ <group expand='0' name="group_by" string='Group by...'>
<filter string='Category' domain="[]" context="{'group_by' : 'categ_id'}"/>
<filter string='Default Unit of Measure' icon="terp-mrp" domain="[]" context="{'group_by' : 'uom_id'}"/>
<filter string='Type' icon="terp-stock_symbol-selection" domain="[]" context="{'group_by' : 'type'}"/>
@@ -53,18 +53,15 @@
<field name='product_variant_count' invisible='1'/>
<sheet>
<field name="id" invisible="True"/>
- <div class="oe_right oe_button_box" style="width: 300px;" name="buttons">
- </div>
- <div class="oe_left" style="width: 500px;">
- <field name="image_medium" widget="image" class="oe_avatar oe_left"/>
- <div class="oe_title" style="width: 390px;">
- <label class="oe_edit_only" for="name" string="Product Name"/>
- <h1><field name="name" class="oe_inline"/></h1>
- <div name="options" groups="base.group_user">
- <div>
- <field name="sale_ok"/>
- <label for="sale_ok"/>
- </div>
+ <div class="oe_button_box" name="button_box"/>
+ <field name="image_medium" widget="image" class="oe_avatar"/>
+ <div class="oe_title">
+ <label class="oe_edit_only" for="name" string="Product Name"/>
+ <h1><field name="name"/></h1>
+ <div name="options" groups="base.group_user">
+ <div>
+ <field name="sale_ok"/>
+ <label for="sale_ok"/>
</div>
</div>
</div>
@@ -161,7 +158,7 @@
<field name="name" position="after">
<field name="product_tmpl_id" string="Product Template"/>
</field>
- <xpath expr="//group[@string='Group by...']" position="inside">
+ <xpath expr="//group[@name='group_by']" position="inside">
<filter string='Product Template' name="template_id" domain="[]" context="{'group_by' : 'product_tmpl_id'}"/>
</xpath>
</field>
@@ -255,14 +252,14 @@
<field name="barcode" attrs="{'invisible': [('product_variant_count', '>', 1)]}"/>
<field name="default_code" attrs="{'invisible': [('product_variant_count', '>', 1)]}"/>
</field>
- <xpath expr="//page[@string='Sales']" position="after">
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" string="Variant Prices" name="%(variants_template_action)d" type="action" icon="fa-strikethrough"/>
+ <button class="oe_stat_button" name="%(product.product_variant_action)d" type="action" icon="fa-sitemap">
+ <field string="List of Variants" name="product_variant_count" widget="statinfo" />
+ </button>
+ </div>
+ <xpath expr="//page[@name='sales']" position="after">
<page name="variants" string="Variants">
- <div class="oe_right">
- <button class="oe_inline oe_stat_button" string="Variant Prices" name="%(variants_template_action)d" type="action" icon="fa-strikethrough"/>
- <button class="oe_inline oe_stat_button" name="%(product.product_variant_action)d" type="action" icon="fa-sitemap">
- <field string="List of Variants" name="product_variant_count" widget="statinfo" />
- </button>
- </div>
<p class="oe_grey">
<strong>Warning</strong>: adding or deleting attributes
will delete and recreate existing variants and lead
@@ -291,8 +288,8 @@
<field name="product_variant_ids"/>
<templates>
<t t-name="kanban-box">
- <div class="oe_kanban_vignette oe_semantic_html_override">
- <a type="open"><img t-att-src="kanban_image('product.template', 'image_small', record.id.value)" class="oe_kanban_image"/></a>
+ <div class="o_kanban_two_column">
+ <a type="open"><img t-att-src="kanban_image('product.template', 'image_small', record.id.value)" class="o_kanban_image"/></a>
<div class="oe_kanban_details">
<h4>
<a type="open">
@@ -867,4 +864,4 @@
</record>
</data>
-</openerp>
+</openerp> \ No newline at end of file
diff --git a/addons/project/project.py b/addons/project/project.py
index b75a0e2fa95..fdffb68ed86 100644
--- a/addons/project/project.py
+++ b/addons/project/project.py
@@ -556,6 +556,12 @@ class task(osv.osv):
res[task.id] = False
return res
+ def _compute_displayed_image(self, cr, uid, ids, prop, arg, context=None):
+ res = {}
+ for line in self.browse(cr, uid, ids, context=context):
+ res[line.id] = line.attachment_ids and line.attachment_ids.filtered(lambda x: x.file_type_icon == 'webimage')[0] or None
+ return res
+
_columns = {
'active': fields.function(_is_template, store=True, string='Not a Template Task', type='boolean', help="This field is computed automatically and have the same behavior than the boolean 'active' field: if the task is linked to a template or unactivated project, it will be hidden unless specifically asked."),
'name': fields.char('Task Summary', track_visibility='onchange', size=128, required=True, select=True),
@@ -592,7 +598,9 @@ class task(osv.osv):
'id': fields.integer('ID', readonly=True),
'color': fields.integer('Color Index'),
'user_email': fields.related('user_id', 'email', type='char', string='User Email', readonly=True),
- }
+ 'attachment_ids': fields.one2many('ir.attachment', 'res_id', domain=lambda self: [('res_model', '=', self._name)], auto_join=True, string='Attachments'),
+ 'displayed_image_id': fields.function(_compute_displayed_image, relation='ir.attachment', type="many2one", string='Attachment'),
+ }
_defaults = {
'stage_id': _get_default_stage_id,
'project_id': lambda self, cr, uid, ctx=None: ctx.get('default_project_id') if ctx is not None else False,
diff --git a/addons/project/project_dashboard.xml b/addons/project/project_dashboard.xml
index 1e5ccbd13bc..9d23ad05f40 100644
--- a/addons/project/project_dashboard.xml
+++ b/addons/project/project_dashboard.xml
@@ -27,7 +27,7 @@
<span><t t-esc="record.name.value"/></span>
</div>
<div t-if="record.alias_id.raw_value">
- <span><i class="fa fa-envelope-o"></i> <t t-esc="record.alias_id.value"/></span>
+ <span><i class="fa fa-envelope"></i> <t t-esc="record.alias_id.value"/></span>
</div>
</div>
</div><div class="o_kanban_card_manage_pane o_invisible">
@@ -41,16 +41,14 @@
<div>
<a name="%(action_view_task_history_cumulative_filter)d" type="action">Cumulative Flow</a>
</div>
- </div>
- <div t-if="widget.view.is_action_enabled('edit')" class="o_project_kanban_colorpicker">
- <div class="col-xs-12">
- <li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
+ <div t-if="widget.editable" class="o_project_kanban_colorpicker">
+ <ul class="oe_kanban_colorpicker" data-field="color"/>
</div>
</div>
</div>
<div class="o_project_kanban_manage">
<div class="text-left">
- <a class="o_kanban_manage_toggle_button">More <i class="fa fa-caret-down"/></a>
+ <a class="o_kanban_manage_toggle_button" href="#">More <i class="fa fa-caret-down"/></a>
</div>
</div>
</div>
diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml
index 5861df6869a..36ff5bccf03 100644
--- a/addons/project/project_view.xml
+++ b/addons/project/project_view.xml
@@ -7,6 +7,7 @@
id="base.menu_main_pm"
groups="group_project_manager,group_project_user"
icon="fa-calendar"
+ web_icon="project,static/description/icon.png"
sequence="50"/>
<menuitem name="Search"
@@ -88,6 +89,15 @@
</header>
<sheet string="Project">
<field name="analytic_account_id" invisible="1" required="0"/>
+ <div class="oe_button_box" name="button_box" groups="base.group_user">
+ <button class="oe_stat_button" type="action" attrs="{'invisible':[('use_tasks','=', False)]}"
+ name="%(act_project_project_2_project_task_all)d" icon="fa-tasks">
+ <field string="Tasks" name="task_count" widget="statinfo" options="{'label_field': 'label_tasks'}"/>
+ </button>
+ <button class="oe_stat_button" name="attachment_tree_view" type="object" icon="fa-files-o">
+ <field string="Documents" name="doc_count" widget="statinfo"/>
+ </button>
+ </div>
<div class="oe_title">
<label for="name" class="oe_edit_only" string="Project Name"/>
<h1>
@@ -102,15 +112,6 @@
</div>
</div>
</div>
- <div class="oe_right oe_button_box" name="buttons" groups="base.group_user">
- <button class="oe_inline oe_stat_button" type="action" attrs="{'invisible':[('use_tasks','=', False)]}"
- name="%(act_project_project_2_project_task_all)d" icon="fa-tasks">
- <field string="Tasks" name="task_count" widget="statinfo" options="{'label_field': 'label_tasks'}"/>
- </button>
- <button class="oe_inline oe_stat_button" name="attachment_tree_view" type="object" icon="fa-files-o">
- <field string="Documents" name="doc_count" widget="statinfo"/>
- </button>
- </div>
<notebook>
<page string="Emails" attrs="{'invisible': [('alias_domain', '=', False)]}">
<group name="group_alias">
@@ -254,7 +255,6 @@
</record>
<!-- Task -->
-
<record id="view_task_form2" model="ir.ui.view">
<field name="name">project.task.form</field>
<field name="model">project.task</field>
@@ -266,17 +266,15 @@
options="{'fold_field': 'fold'}"/>
</header>
<sheet string="Task">
- <div class="row">
- <h1 class="col-xs-11">
- <field class="oe_inline oe_left" name="priority" widget="priority"/>
- <field name="name" placeholder="Task summary..." class="oe_inline"/>
- </h1>
- <div class="col-xs-1 text-right">
- <field name="kanban_state" class="oe_inline" widget="kanban_state_selection"
+ <div class="oe_title">
+ <h1 class="o_row">
+ <field name="priority" widget="priority"/>
+ <field name="name" placeholder="Task summary..."/>
+ <field name="kanban_state" widget="kanban_state_selection"
options='{
"states_legend_field": "stage_id",
"states_legend": {"normal": "legend_normal", "blocked": "legend_blocked", "done": "legend_done"}}'/>
- </div>
+ </h1>
</div>
<group>
<group>
@@ -357,29 +355,35 @@
<field name="date_deadline"/>
<field name="message_summary"/>
<field name="tag_ids"/>
+ <field name="displayed_image_id"/>
<templates>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_card oe_kanban_global_click">
- <div class="oe_dropdown_toggle oe_dropdown_kanban" groups="base.group_user">
- <i class="fa fa-bars fa-lg"/>
- <ul class="oe_dropdown_menu">
- <t t-if="widget.view.is_action_enabled('edit')"><li><a type="edit">Edit Task</a></li></t>
- <t t-if="widget.view.is_action_enabled('delete')"><li><a type="delete">Delete</a></li></t>
+
+ <div class="o_dropdown_kanban dropdown" groups="base.group_user">
+ <a class="dropdown-toggle btn" data-toggle="dropdown" href="#" >
+ <span class="fa fa-bars fa-lg"/>
+ </a>
+ <ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
+ <t t-if="widget.editable"><li><a type="edit">Edit Task</a></li></t>
+ <t t-if="widget.deletable"><li><a type="delete">Delete</a></li></t>
<li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
</ul>
</div>
-
<div class="oe_kanban_content">
- <div><b><field name="name"/></b></div>
<div>
+ <field name="tag_ids"/>
+ </div>
+ <div>
+ <strong><field name="name"/></strong>
+ </div>
+ <div class="text-muted">
<field name="project_id" invisible="context.get('default_project_id', False)"/><br/>
<t t-if="record.date_deadline.raw_value and record.date_deadline.raw_value lt (new Date())" t-set="red">oe_kanban_text_red</t>
<span t-attf-class="#{red || ''}"><i><field name="date_deadline"/></i></span>
</div>
- <div class="oe_kanban_footer_left" style="margin-top:5px;">
- <field name="tag_ids"/>
- </div>
<div class="oe_kanban_bottom_left">
+ <field name="priority" widget="priority"/>
<t t-raw="record.message_summary.raw_value"/>
</div>
<div class="oe_kanban_bottom_right">
@@ -387,10 +391,12 @@
<div class="pull-left" groups="base.group_user">
<field name="kanban_state" widget="kanban_state_selection"
options='{"states_legend": {"normal": "legend_normal", "blocked": "legend_blocked", "done": "legend_done"}}'/>
- <field name="priority" widget="priority"/>
</div>
</div>
</div>
+ <div t-if="record.displayed_image_id.value">
+ <field name="displayed_image_id" widget="attachment_image"/>
+ </div>
<div class="oe_clear"></div>
</div>
</t>
@@ -571,7 +577,7 @@
<p class="text-muted" colspan="2">
You can also give a tooltip about the use of the stars available in the kanban and form views.
</p>
- <label for="legend_priority" string=" " class="fa fa-star fa-lg oe_star_on oe_project_kanban_legend"/>
+ <label for="legend_priority" string=" " class="fa fa-star fa-lg o_star_on oe_project_kanban_legend"/>
<field name="legend_priority" nolabel="1"/>
<p class="text-muted" colspan="2">
@@ -685,4 +691,4 @@
<menuitem action="project_tags_action" id="menu_project_tags_act" parent="base.menu_definitions" groups="base.group_no_one"/>
</data>
-</openerp>
+</openerp> \ No newline at end of file
diff --git a/addons/project/res_partner_view.xml b/addons/project/res_partner_view.xml
index ed52b8bcaf7..82448073bf1 100644
--- a/addons/project/res_partner_view.xml
+++ b/addons/project/res_partner_view.xml
@@ -10,17 +10,15 @@
<field name="priority" eval="50"/>
<field name="groups_id" eval="[(4, ref('project.group_project_user'))]"/>
<field name="arch" type="xml">
- <xpath expr="//div[@name='buttons']" position="inside">
- <button class="oe_inline oe_stat_button" type="action" name="%(action_view_task)d"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" type="action" name="%(action_view_task)d"
context="{'search_default_partner_id': active_id, 'default_partner_id': active_id}"
icon="fa-tasks">
<field string="Tasks" name="task_count" widget="statinfo"/>
- </button>
-
-
- </xpath>
+ </button>
+ </div>
</field>
</record>
</data>
-</openerp>
+</openerp> \ No newline at end of file
diff --git a/addons/project/static/src/js/project.js b/addons/project/static/src/js/project.js
index 20927cebc2c..515918df0b0 100644
--- a/addons/project/static/src/js/project.js
+++ b/addons/project/static/src/js/project.js
@@ -1,14 +1,14 @@
odoo.define('project.update_kanban', function (require) {
-var kanban_common = require('web_kanban.common');
+var KanbanRecord = require('web_kanban.Record');
var KanbanView = require('web_kanban.KanbanView');
var data = require('web.data');
var session = require('web.session');
-kanban_common.KanbanRecord.include({
+KanbanRecord.include({
on_card_clicked: function() {
- if (this.view.dataset.model === 'project.project') {
+ if (this.model === 'project.project') {
this.$('.o_project_kanban_boxes a').first().click();
} else {
this._super.apply(this, arguments);
diff --git a/addons/project/static/src/less/project_dashboard.less b/addons/project/static/src/less/project_dashboard.less
index 9ce363aea0a..e47f36a4f0a 100644
--- a/addons/project/static/src/less/project_dashboard.less
+++ b/addons/project/static/src/less/project_dashboard.less
@@ -1,45 +1,37 @@
-.oe_kanban_view.o_kanban_dashboard.o_project_kanban {
-
- @odoo-brand-optional: #21b799;
+.o_kanban_view.o_kanban_dashboard.o_project_kanban {
.o_kanban_flexbox {
- display: flex;
+ .o-flex-display();
position: relative;
}
- .oe_kanban_record {
+ .o_kanban_record {
min-width: 300px;
- max-width: 350px;
- }
-
- /*
- .oe_kanban_record:hover .o_project_kanban_manage {
- visibility: visible;
}
- */
.o_project_kanban_main {
- margin-bottom: 40px; // give space for manage section at the bottom
- width: 75%;
+ // give space for manage section at the bottom
+ margin-bottom: 40px;
+ width: 70%;
- .o_primary {
- font-size: larger;
+ .o_kanban_card_content {
+ font-size: 12px;
+ .o_primary {
+ font-size: larger;
+ }
}
.o_project_kanban_manage {
visibility: visible;
position: absolute;
bottom: 0;
- margin-left: 10px;
+ margin-left: 16px;
margin-bottom: 10px;
}
.o_project_kanban_colorpicker {
padding: 8px;
}
.o_kanban_card_manage_pane {
- border-color: lightgrey;
- border-bottom-style: solid;
- border-bottom-width: 1px;
.o_kanban_card_manage_title {
margin: 0;
@@ -48,12 +40,16 @@
}
.o_project_kanban_boxes {
- display: flex;
- flex-direction: column;
- justify-content: flex-end;
- align-content: stretch;
+ .o-flex-display();
+ .o-flex-flow(column, nowrap);
+ .o-justify-content(flex-end);
+ .o-align-content(stretch);
+
+ width: 30%;
- width: 25%;
+ > a:hover {
+ text-decoration: none;
+ }
.o_value {
font-size: x-large;
@@ -67,11 +63,11 @@
.o_project_kanban_box {
text-align: center;
padding: 15px 0 15px 0;
- flex: 1 1 auto;
- display: flex;
- align-items: center;
- flex-direction: column;
- justify-content: center;
+ .o-flex(1, 1, auto);
+ .o-flex-display();
+ .o-align-items(center);
+ .o-flex-flow(column, nowrap);
+ .o-justify-content(center);
}
.o_project_kanban_box:nth-child(even) {
background-color: grey;
@@ -80,4 +76,4 @@
background-color: @odoo-brand-optional;
}
}
-}
+} \ No newline at end of file
diff --git a/addons/project_issue/project_issue_view.xml b/addons/project_issue/project_issue_view.xml
index cd4675a1ae3..b9b03b0bf60 100644
--- a/addons/project_issue/project_issue_view.xml
+++ b/addons/project_issue/project_issue_view.xml
@@ -36,7 +36,7 @@
<div name="project">
<field name="project_id" on_change="on_change_project(project_id)" class="oe_inline" context="{'default_use_issues':1}"/>
<field name="can_escalate" invisible="1"/>
- <button name="case_escalate" string="Escalate" type="object" class="oe_link" attrs="{'invisible':[('can_escalate','=',False)]}" groups="base.group_user"/>
+ <button name="case_escalate" string="Escalate" type="object" class="btn-default" attrs="{'invisible':[('can_escalate','=',False)]}" groups="base.group_user"/>
</div>
</group>
<group>
@@ -168,8 +168,8 @@
<div class="oe_dropdown_toggle oe_dropdown_kanban" groups="base.group_user">
<i class="fa fa-bars fa-lg"/>
<ul class="oe_dropdown_menu">
- <t t-if="widget.view.is_action_enabled('edit')"><li><a type="edit">Edit Issue</a></li></t>
- <t t-if="widget.view.is_action_enabled('delete')"><li><a type="delete">Delete</a></li></t>
+ <t t-if="widget.editable"><li><a type="edit">Edit Issue</a></li></t>
+ <t t-if="widget.deletable"><li><a type="delete">Delete</a></li></t>
<li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
</ul>
</div>
@@ -278,12 +278,12 @@
<field name="label_issues" class="oe_inline oe_input_align" attrs="{'invisible': [('use_issues', '=', False)]}"/>
</div>
</xpath>
- <xpath expr='//div[@name="buttons"]' position='inside'>
- <button class="oe_inline oe_stat_button" type="action" attrs="{'invisible':[('use_issues','=', False)]}"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" type="action" attrs="{'invisible':[('use_issues','=', False)]}"
name="%(act_project_project_2_project_issue_all)d" icon="fa-bug">
<field string="Issues" name="issue_count" widget="statinfo" options="{'label_field': 'label_issues'}"/>
</button>
- </xpath>
+ </div>
<xpath expr='//page[@name="project_stages"]' position="attributes">
<attribute name="attrs">{'invisible': [('use_tasks', '=', False),('use_issues','=',False)]}</attribute>
</xpath>
@@ -331,18 +331,16 @@
<field name="priority" eval="50"/>
<field name="groups_id" eval="[(4, ref('project.group_project_user'))]"/>
<field name="arch" type="xml">
- <xpath expr="//div[@name='buttons']" position="inside">
- <button class="oe_inline oe_stat_button" type="action" name="%(action_view_issues)d"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" type="action" name="%(action_view_issues)d"
context="{'search_default_partner_id': active_id, 'default_partner_id': active_id}"
attrs="{'invisible': [('customer', '=', False)]}"
icon="fa-bug">
<field string="Issues" name="issue_count" widget="statinfo"/>
</button>
-
-
- </xpath>
+ </div>
</field>
</record>
</data>
-</openerp>
+</openerp> \ No newline at end of file
diff --git a/addons/project_timesheet/project_timesheet_view.xml b/addons/project_timesheet/project_timesheet_view.xml
index 35b72c3773d..0d1d4cb7f99 100644
--- a/addons/project_timesheet/project_timesheet_view.xml
+++ b/addons/project_timesheet/project_timesheet_view.xml
@@ -40,10 +40,10 @@
<field name="effective_hours" widget="float_time"
groups="project.group_time_work_estimation_tasks"/>
</field>
- <xpath expr='//div[@name="buttons"]' position="inside">
- <button class="oe_inline oe_stat_button" name="open_timesheets" type="object" attrs="{'invisible':[('invoice_on_timesheets','=',False)]}"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" name="open_timesheets" type="object" attrs="{'invisible':[('invoice_on_timesheets','=',False)]}"
icon="fa-calendar" string="Timesheets"/>
- </xpath>
+ </div>
<xpath expr='//field[@name="partner_id"]' position='after'>
<field name="pricelist_id" invisible="1"/>
</xpath>
diff --git a/addons/purchase/partner_view.xml b/addons/purchase/partner_view.xml
index 060a7e3a2fa..a7a3d4a53ef 100644
--- a/addons/purchase/partner_view.xml
+++ b/addons/purchase/partner_view.xml
@@ -77,12 +77,12 @@
<field name="priority" eval="20"/>
<field name="groups_id" eval="[(4, ref('purchase.group_purchase_user'))]"/>
<field name="arch" type="xml">
- <xpath expr="//div[@name='buttons']" position="inside">
- <button class="oe_inline oe_stat_button" name="%(purchase.act_res_partner_2_purchase_order)d" type="action"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" name="%(purchase.act_res_partner_2_purchase_order)d" type="action"
attrs="{'invisible': [('supplier', '=', False)]}" icon="fa-shopping-cart">
<field string="Purchases" name="purchase_order_count" widget="statinfo"/>
</button>
- </xpath>
+ </div>
</field>
</record>
@@ -93,12 +93,12 @@
<field name="priority" eval="20"/>
<field name="groups_id" eval="[(4, ref('account.group_account_user'))]"/>
<field name="arch" type="xml">
- <xpath expr="//div[@name='buttons']" position="inside">
- <button class="oe_inline oe_stat_button" name="%(purchase.act_res_partner_2_supplier_invoices)d" type="action"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" name="%(purchase.act_res_partner_2_supplier_invoices)d" type="action"
attrs="{'invisible': [('supplier', '=', False)]}" icon="fa-pencil-square-o" help="Supplier Bills">
<field string="Supplier Inv." name="supplier_invoice_count" widget="statinfo"/>
</button>
- </xpath>
+ </div>
</field>
</record>
</data>
diff --git a/addons/purchase/purchase_view.xml b/addons/purchase/purchase_view.xml
index af3de1e53ff..0b33340797b 100644
--- a/addons/purchase/purchase_view.xml
+++ b/addons/purchase/purchase_view.xml
@@ -694,12 +694,12 @@
<field name="inherit_id" ref="product.product_template_only_form_view"/>
<field name="groups_id" eval="[(4, ref('purchase.group_purchase_user'))]"/>
<field name="arch" type="xml">
- <xpath expr="//div[@name='buttons']" position="inside">
- <button class="oe_inline oe_stat_button" name="action_view_purchases" type="object"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" name="action_view_purchases" type="object"
icon="fa-shopping-cart">
<field string="Purchases" name="purchase_count" widget="statinfo"/>
</button>
- </xpath>
+ </div>
</field>
</record>
@@ -709,12 +709,12 @@
<field name="inherit_id" ref="product.product_normal_form_view"/>
<field name="groups_id" eval="[(4, ref('purchase.group_purchase_user'))]"/>
<field name="arch" type="xml">
- <xpath expr="//div[@name='buttons']" position="inside">
- <button class="oe_inline oe_stat_button" name="action_view_purchases" type="object"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" name="action_view_purchases" type="object"
icon="fa-shopping-cart">
<field string="Purchases" name="purchase_count" widget="statinfo"/>
</button>
- </xpath>
+ </div>
</field>
</record>
diff --git a/addons/purchase/stock_view.xml b/addons/purchase/stock_view.xml
index 1e40b0398cb..1021550734f 100644
--- a/addons/purchase/stock_view.xml
+++ b/addons/purchase/stock_view.xml
@@ -30,7 +30,7 @@
<field name="inherit_id" ref="purchase.purchase_order_form"/>
<field name="arch" type="xml">
<xpath expr="//div[contains(@class, 'oe_title')]" position="before">
- <div class="oe_right oe_button_box" name="buttons">
+ <div class="oe_button_box" name="button_box">
<button type="object"
name="view_picking"
class="oe_stat_button"
diff --git a/addons/purchase_requisition/purchase_requisition_view.xml b/addons/purchase_requisition/purchase_requisition_view.xml
index 9111e262484..14c45fc3cc6 100644
--- a/addons/purchase_requisition/purchase_requisition_view.xml
+++ b/addons/purchase_requisition/purchase_requisition_view.xml
@@ -39,11 +39,14 @@
<field name="state" widget="statusbar" statusbar_visible="draft,in_progress,open,done" statusbar_colors='{"in_progress":"blue"}'/>
</header>
<sheet>
- <div class="oe_right oe_button_box" name="buttons">
+ <div class="oe_button_box" name="button_box">
<button name="open_product_line" type="object" string="Product Lines" class="oe_stat_button" icon="fa-list"
attrs="{'invisible': ['|', ('state', 'not in', ('open','done')), ('exclusive', '=', 'exclusive')]}" groups="purchase.group_advance_bidding"/>
<button name="open_rfq" type="object" string="RFQs/Bids" class="oe_stat_button" icon="fa-list-alt"
attrs="{'invisible': [('state', '=', 'draft')]}"/>
+ <button name="%(action_purchase_requisition_partner)d" type="action"
+ string="Request a Quotation" icon="gtk-execute"
+ attrs="{'invisible': ['|', ('line_ids','=',[]),('state', 'in', ('draft' ,'open','done'))]}"/>
</div>
<div class="pull-left">
<label for="name" class="oe_edit_only oe_inline"/>
@@ -89,11 +92,6 @@
</group>
</form>
</field>
- <div class="oe_right oe_button_box" style="margin-top: 10px">
- <button name="%(action_purchase_requisition_partner)d" type="action"
- string="Request a Quotation" icon="gtk-execute"
- attrs="{'invisible': ['|', ('line_ids','=',[]),('state', 'in', ('draft' ,'open','done'))]}"/>
- </div>
<separator string="Requests for Quotation"/>
<field name="purchase_ids" options="{'reload_on_button': true}">
<tree string="Purchase Order">
diff --git a/addons/rating/static/src/js/rating.js b/addons/rating/static/src/js/rating.js
index 87f16cd1a50..91447bd1be7 100644
--- a/addons/rating/static/src/js/rating.js
+++ b/addons/rating/static/src/js/rating.js
@@ -1,11 +1,11 @@
odoo.define('rating.kanban', function(require) {
"use strict";
-var common = require('web_kanban.common');
+var KanbanRecord = require('web_kanban.Record');
-common.KanbanRecord.include({
+KanbanRecord.include({
on_card_clicked: function() {
- if (this.view.dataset.model === 'rating.rating') {
+ if (this.model === 'rating.rating') {
this.$('a').first().click();
} else {
this._super.apply(this, arguments);
diff --git a/addons/rating_project/views/project_view.xml b/addons/rating_project/views/project_view.xml
index 8322dd0b096..8f56709d83f 100644
--- a/addons/rating_project/views/project_view.xml
+++ b/addons/rating_project/views/project_view.xml
@@ -8,7 +8,7 @@
<field name="inherit_id" ref="project.edit_project"/>
<field name="priority" eval="20"/>
<field name="arch" type="xml">
- <xpath expr="//div[@name='buttons']" position="inside">
+ <div name="button_box" position="inside">
<button name="action_view_task_rating"
attrs="{'invisible': ['|', '|', ('is_visible_happy_customer', '=', False), ('use_tasks','=', False), ('percentage_satisfaction_task', '=', -1)]}"
class="oe_stat_button oe_percent"
@@ -16,7 +16,7 @@
icon="fa-smile-o">
<field string="On tasks" name="percentage_satisfaction_task" widget="statinfo"/>
</button>
- </xpath>
+ </div>
<xpath expr="//field[@name='privacy_visibility']" position="after">
<field name="is_visible_happy_customer"/>
</xpath>
@@ -38,4 +38,4 @@
</record>
</data>
-</openerp>
+</openerp> \ No newline at end of file
diff --git a/addons/rating_project_issue/views/project_issue_view.xml b/addons/rating_project_issue/views/project_issue_view.xml
index 0f16b3bb460..660886e8b80 100644
--- a/addons/rating_project_issue/views/project_issue_view.xml
+++ b/addons/rating_project_issue/views/project_issue_view.xml
@@ -8,7 +8,7 @@
<field name="inherit_id" ref="project.edit_project"/>
<field name="priority" eval="20"/>
<field name="arch" type="xml">
- <xpath expr="//div[@name='buttons']" position="inside">
+ <div name="button_box" position="inside">
<button name="action_view_issue_rating"
attrs="{'invisible': ['|', '|', ('use_issues','=', False), ('is_visible_happy_customer','=', False), ('percentage_satisfaction_issue', '=', -1)]}"
class="oe_stat_button oe_percent"
@@ -16,7 +16,7 @@
icon="fa-smile-o">
<field string="On issues" name="percentage_satisfaction_issue" widget="statinfo"/>
</button>
- </xpath>
+ </div>
</field>
</record>
diff --git a/addons/sale/res_partner_view.xml b/addons/sale/res_partner_view.xml
index 2f08c015d2a..3c6fb2468f4 100644
--- a/addons/sale/res_partner_view.xml
+++ b/addons/sale/res_partner_view.xml
@@ -34,9 +34,7 @@
<field name="sale_order_count"/>
</field>
<xpath expr="//div[@class='oe_kanban_partner_links']" position="inside">
- <a name="%(sale.act_res_partner_2_sale_order)d" type="action" t-if="record.sale_order_count.value>0">
- <t t-esc="record.sale_order_count.value"/> Sales
- </a>
+ <span t-if="record.sale_order_count.value>0" class="badge"><i class="fa fa-fw fa-strikethrough"/><t t-esc="record.sale_order_count.value"/></span>
</xpath>
</field>
</record>
@@ -48,16 +46,15 @@
<field name="priority" eval="20"/>
<field name="groups_id" eval="[(4, ref('base.group_sale_salesman'))]"/>
<field name="arch" type="xml">
- <xpath expr="//div[@name='buttons']" position="inside">
- <button class="oe_inline oe_stat_button" type="action" name="%(sale.act_res_partner_2_sale_order)d"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" type="action" name="%(sale.act_res_partner_2_sale_order)d"
attrs="{'invisible': [('customer', '=', False)]}"
icon="fa-strikethrough">
<field string="Sales" name="sale_order_count" widget="statinfo"/>
</button>
- </xpath>
+ </div>
</field>
</record>
</data>
</openerp>
-
diff --git a/addons/sale/sale_view.xml b/addons/sale/sale_view.xml
index 79aa32f2075..8e20b5c5e36 100644
--- a/addons/sale/sale_view.xml
+++ b/addons/sale/sale_view.xml
@@ -143,14 +143,7 @@
<field name="state" widget="statusbar" statusbar_visible="draft,sent,progress,done" statusbar_colors='{"invoice_except":"red","waiting_date":"blue"}'/>
</header>
<sheet>
- <div class="oe_title">
- <h1>
- <label string="Quotation " attrs="{'invisible': [('state', 'not in', ('draft', 'sent'))]}"/>
- <label string="Sales Order " attrs="{'invisible': [('state', 'in', ('draft', 'sent'))]}"/>
- <field name="name" class="oe_inline" readonly="1"/>
- </h1>
- </div>
- <div class="oe_right oe_button_box" name="buttons">
+ <div class="oe_button_box" name="button_box">
<button name="action_view_invoice"
type="object"
class="oe_stat_button"
@@ -159,6 +152,13 @@
<field name="invoice_count" widget="statinfo" string="Invoices"/>
</button>
</div>
+ <div class="oe_title">
+ <h1>
+ <label string="Quotation " attrs="{'invisible': [('state', 'not in', ('draft', 'sent'))]}"/>
+ <label string="Sales Order " attrs="{'invisible': [('state', 'in', ('draft', 'sent'))]}"/>
+ <field name="name" class="oe_inline" readonly="1"/>
+ </h1>
+ </div>
<group>
<group>
<field name="partner_id" on_change="onchange_partner_id(partner_id, context)" domain="[('customer','=',True)]" context="{'search_default_customer':1, 'show_address': 1}" options='{"always_reload": True}'/>
@@ -591,12 +591,12 @@
<field name="inherit_id" ref="product.product_normal_form_view"/>
<field name="groups_id" eval="[(4, ref('base.group_sale_salesman'))]"/>
<field name="arch" type="xml">
- <xpath expr="//div[@name='buttons']" position="inside">
- <button class="oe_inline oe_stat_button" name="action_view_sales"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" name="action_view_sales"
type="object" icon="fa-strikethrough">
<field string="Sales" name="sales_count" widget="statinfo" />
</button>
- </xpath>
+ </div>
</field>
</record>
@@ -606,12 +606,12 @@
<field name="inherit_id" ref="product.product_template_only_form_view"/>
<field name="groups_id" eval="[(4, ref('base.group_sale_salesman'))]"/>
<field name="arch" type="xml">
- <xpath expr="//div[@name='buttons']" position="inside">
- <button class="oe_inline oe_stat_button" name="action_view_sales"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" name="action_view_sales"
type="object" icon="fa-strikethrough">
<field string="Sales" name="sales_count" widget="statinfo" />
</button>
- </xpath>
+ </div>
</field>
</record>
diff --git a/addons/sale_crm/sale_crm_view.xml b/addons/sale_crm/sale_crm_view.xml
index 3f63289c592..92e4afe329c 100644
--- a/addons/sale_crm/sale_crm_view.xml
+++ b/addons/sale_crm/sale_crm_view.xml
@@ -29,21 +29,21 @@
<button attrs="{'invisible': [('probability', '>', 0)]}" string="New Quotation" name="%(sale_action_quotations_new)d" type="action"
context="{'search_default_partner_id': partner_id, 'default_partner_id': partner_id}"/>
</xpath>
- <xpath expr="//div[@name='buttons']" position="inside">
- <button class="oe_inline oe_stat_button" type="action"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" type="action"
name="%(sale_action_quotations)d" icon="stat_button_icon fa fa-usd"
context="{'search_default_partner_id': partner_id, 'default_partner_id': partner_id}">
<field name="sale_number" widget="statinfo" string="Quotes"/>
</button>
- <button class="oe_inline oe_stat_button" type="action" attrs="{'invisible': [('sale_amount_total', '=', 0)]}"
+ <button class="oe_stat_button" type="action" attrs="{'invisible': [('sale_amount_total', '=', 0)]}"
name="%(sale_action_quotations)d" icon="stat_button_icon fa fa-usd"
context="{'search_default_partner_id': partner_id, 'default_partner_id': partner_id}">
- <div>
- <strong><field name="sale_amount_total" class="oe_inline" widget="monetary" options="{'currency_field': 'company_currency'}"/></strong>
- <div><field name="sale_number" class="oe_inline"/> Orders</div>
+ <div class="o_form_field o_stat_info">
+ <span class="o_stat_value"><field name="sale_amount_total" widget="monetary" options="{'currency_field': 'company_currency'}"/></span>
+ <span class="o_stat_text"> Orders</span>
</div>
</button>
- </xpath>
+ </div>
</data>
</field>
</record>
diff --git a/addons/sales_team/sales_team_dashboard.xml b/addons/sales_team/sales_team_dashboard.xml
index fa14cd91284..33e5a7062c5 100644
--- a/addons/sales_team/sales_team_dashboard.xml
+++ b/addons/sales_team/sales_team_dashboard.xml
@@ -47,7 +47,7 @@
</div>
</div>
- <div t-if="widget.view.is_action_enabled('edit')" class="o_kanban_card_manage_settings row">
+ <div t-if="widget.editable" class="o_kanban_card_manage_settings row">
<div class="col-xs-8">
<li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
</div>
diff --git a/addons/sales_team/static/src/js/sales_team.js b/addons/sales_team/static/src/js/sales_team.js
index 40f976a465a..0000fbdc7be 100644
--- a/addons/sales_team/static/src/js/sales_team.js
+++ b/addons/sales_team/static/src/js/sales_team.js
@@ -2,7 +2,7 @@ odoo.define('sales_team.update_kanban', function (require) {
"use strict";
var KanbanView = require('web_kanban.KanbanView');
-var kanban_common = require('web_kanban.common');
+var KanbanRecord = require('web_kanban.Record');
var data = require('web.data');
var session = require('web.session');
@@ -40,9 +40,9 @@ KanbanView.include({
},
});
-kanban_common.KanbanRecord.include({
+KanbanRecord.include({
on_card_clicked: function() {
- if (this.view.dataset.model === 'crm.team') {
+ if (this.model === 'crm.team') {
this.$('.oe_kanban_crm_salesteams_list a').first().click();
} else {
this._super.apply(this, arguments);
diff --git a/addons/stock/product_view.xml b/addons/stock/product_view.xml
index a22e11d5945..f7c2bd06efd 100644
--- a/addons/stock/product_view.xml
+++ b/addons/stock/product_view.xml
@@ -222,18 +222,18 @@
<field name="model">product.product</field>
<field name="inherit_id" ref="product.product_normal_form_view"/>
<field name="arch" type="xml">
- <xpath expr="//div[@name='buttons']" position="inside">
+ <div name="button_box" position="inside">
<button class="oe_stat_button"
name="%(product_open_quants)d"
icon="fa-building-o"
type="action" attrs="{'invisible':[('type', '=', 'service')]}" groups="stock.group_locations">
<field name="qty_available2" widget="statinfo"/>
</button>
- <button class="oe_inline oe_stat_button" string="Moves" name= "%(act_product_stock_move_open)d" type="action" attrs="{'invisible':[('type', '=', 'service')]}" groups="stock.group_stock_user" icon="fa-arrows-v"/>
- <button class="oe_inline oe_stat_button" name="%(product_open_orderpoint)d" type="action"
+ <button class="oe_stat_button" string="Moves" name= "%(act_product_stock_move_open)d" type="action" attrs="{'invisible':[('type', '=', 'service')]}" groups="stock.group_stock_user" icon="fa-arrows-v"/>
+ <button class="oe_stat_button" name="%(product_open_orderpoint)d" type="action"
attrs="{'invisible':[('type', '=', 'service')]}" icon="fa-refresh" string="Reordering Rules"/>
- <button class="oe_inline oe_stat_button" name="action_view_routes" string="Routes" type="object" icon="fa-cogs" attrs="{'invisible':[('type', '=', 'service')]}" />
- </xpath>
+ <button class="oe_stat_button" name="action_view_routes" string="Routes" type="object" icon="fa-cogs" attrs="{'invisible':[('type', '=', 'service')]}" />
+ </div>
</field>
</record>
@@ -242,18 +242,18 @@
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_only_form_view"/>
<field name="arch" type="xml">
- <xpath expr="//div[@name='buttons']" position="inside">
+ <div name="button_box" position="inside">
<button class="oe_stat_button"
name="action_open_quants"
icon="fa-building-o"
type="object" attrs="{'invisible':[('type', '=', 'service')]}" groups="stock.group_locations">
<field name="qty_available2" widget="statinfo"/>
</button>
- <button class="oe_inline oe_stat_button" string="Moves" name= "action_view_stock_moves" type="object" attrs="{'invisible':[('type', '=', 'service')]}" groups="stock.group_stock_user" icon="fa-arrows-v"/>
- <button class="oe_inline oe_stat_button" name="action_view_orderpoints" type="object"
+ <button class="oe_stat_button" string="Moves" name= "action_view_stock_moves" type="object" attrs="{'invisible':[('type', '=', 'service')]}" groups="stock.group_stock_user" icon="fa-arrows-v"/>
+ <button class="oe_stat_button" name="action_view_orderpoints" type="object"
attrs="{'invisible':[('type', 'in', ('service','consu'))]}" icon="fa-refresh" string="Reordering Rules"/>
- <button class="oe_inline oe_stat_button" name="action_view_routes" string="Routes" type="object" icon="fa-cogs" attrs="{'invisible':[('type', '=', 'service')]}" />
- </xpath>
+ <button class="oe_stat_button" name="action_view_routes" string="Routes" type="object" icon="fa-cogs" attrs="{'invisible':[('type', '=', 'service')]}" />
+ </div>
</field>
</record>
</data>
diff --git a/addons/stock/stock_dashboard.xml b/addons/stock/stock_dashboard.xml
index ddf35c7beb9..002a7fa3f87 100644
--- a/addons/stock/stock_dashboard.xml
+++ b/addons/stock/stock_dashboard.xml
@@ -100,7 +100,7 @@
</div>
</div>
- <div t-if="widget.view.is_action_enabled('edit')" class="o_kanban_card_manage_settings row">
+ <div t-if="widget.editable" class="o_kanban_card_manage_settings row">
<div class="col-xs-8">
<li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
</div>
diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml
index e0659d35b82..331c3e0c9fe 100644
--- a/addons/stock/stock_view.xml
+++ b/addons/stock/stock_view.xml
@@ -195,7 +195,7 @@
<field name="model">stock.production.lot</field>
<field name="arch" type="xml">
<form string="Serial Number">
- <div class="oe_button_box oe_right">
+ <div class="oe_button_box" name="button_box">
<button name="action_traceability" icon="fa-arrow-up" class="oe_stat_button" string="Traceability" type="object" attrs="{'invisible': [('quant_ids','=',[])]}"/>
</div>
<div class="oe_title">
@@ -316,7 +316,7 @@
<field name="model">stock.location</field>
<field name="arch" type="xml">
<form string="Stock Location">
- <div class="oe_right oe_button_box" name="buttons">
+ <div class="oe_button_box" name="button_box">
<button string="Current Stock"
class="oe_stat_button"
icon="fa-building-o" name="%(location_open_quants)d" type="action"
@@ -532,7 +532,7 @@
<field name="arch" type="xml">
<form string="Warehouse">
<sheet>
- <div class="oe_right oe_button_box">
+ <div class="oe_button_box" name="button_box">
<button name="view_all_routes_for_wh"
string="Routes"
icon="fa-refresh"
@@ -703,7 +703,7 @@
<field name="state" widget="statusbar" statusbar_visible="draft,confirmed,partially_available,assigned,done" statusbar_colors='{"shipping_except":"red","invoice_except":"red","waiting_date":"blue"}'/>
</header>
<sheet>
- <div class="oe_right oe_button_box" name="button_box">
+ <div class="oe_button_box" name="button_box">
</div>
<h1>
<field name="name" class="oe_inline" attrs="{'invisible': [('name','=','/')]}" readonly="1"/>
@@ -1564,7 +1564,7 @@
<field name="arch" type="xml">
<form string="Reordering Rules">
<sheet>
- <div class="oe_right oe_button_box">
+ <div class="oe_button_box" name="button_box">
<button name="action_view_proc_to_process" type="object" string="Procurement Orders to Process"/>
</div>
<group>
@@ -1631,9 +1631,9 @@
<field name="route_ids" widget="many2many_tags"/>
</group>
</xpath>
- <xpath expr="//div[@name='button_box']" position="inside">
+ <div name="button_box" position="inside">
<button name="do_view_pickings" class="oe_stat_button" icon="fa-bars" string="Group's Pickings" type="object"/>
- </xpath>
+ </div>
<xpath expr="//field[@name='rule_id']" position="replace">
<field name="rule_id" domain="['|', ('location_id', '=', False), ('location_id', '=', location_id)]"/>
<field name="partner_dest_id"/>
@@ -1759,8 +1759,8 @@
<field eval="10" name="priority"/>
<field name="arch" type="xml">
<form string="Quants" create="false" edit="false">
- <div class="oe_right oe_button_box">
- <button name="action_view_quant_history" type="object" string="Quant History"/>
+ <div class="oe_button_box" name="button_box">
+ <button name="action_view_quant_history" type="object" string="Quant History"/>
</div>
<group>
<field name="product_id"/>
@@ -1861,11 +1861,12 @@
<field name="arch" type="xml">
<form string="Package">
<sheet>
- <div class="oe_right oe_button_box">
- <button class="oe_inline" name="unpack" string="Unpack" type="object"/>
- <button class="oe_inline oe_stat_button" name="%(action_picking_tree_all)d"
+ <div class="oe_button_box" name="button_box">
+ <button name="unpack" string="Unpack" type="object"/>
+ <button class="oe_stat_button" name="%(action_picking_tree_all)d"
string="Package Transfers" type="action"
widget="statinfo" icon="fa-dropbox"/>
+ <button name="get_content_package" type="object" string="View Contained Packages content" icon="gtk-execute" attrs="{'invisible': [('children_ids','=',[])]}"/>
</div>
<div class="oe_title">
<label for="name" string="Package Reference" class="oe_edit_only"/>
@@ -1895,9 +1896,6 @@
</tree>
</field>
- <div class="oe_right oe_button_box" style="margin-top: 10px">
- <button name="get_content_package" type="object" string="View Contained Packages content" icon="gtk-execute" attrs="{'invisible': [('children_ids','=',[])]}"/>
- </div>
<separator string="Contained Packages"/>
<field name="children_ids">
<tree string="Contained Packages">
@@ -2050,9 +2048,9 @@
<field name="model">procurement.group</field>
<field name="inherit_id" ref="procurement.procurement_group_form_view"/>
<field name="arch" type="xml">
- <xpath expr="//div[@name='button_box']" position="inside">
+ <div name="button_box" position="inside">
<button name="%(do_view_pickings)d" string="Pickings" type="action"/>
- </xpath>
+ </div>
</field>
</record>
diff --git a/addons/stock_picking_wave/stock_picking_wave_view.xml b/addons/stock_picking_wave/stock_picking_wave_view.xml
index b0902e51190..e79bf4b4c8f 100644
--- a/addons/stock_picking_wave/stock_picking_wave_view.xml
+++ b/addons/stock_picking_wave/stock_picking_wave_view.xml
@@ -11,7 +11,7 @@
<field name="state" widget="statusbar" statusbar_visible="in_progress,done"/>
</header>
<sheet>
- <div class="oe_right oe_button_box">
+ <div class="oe_button_box" name="button_box">
<button name="print_picking" string="Print all pickings" type="object"/>
</div>
<div class="oe_title">
diff --git a/addons/survey/views/survey_views.xml b/addons/survey/views/survey_views.xml
index 284de9fc4a9..caa04d18d6f 100644
--- a/addons/survey/views/survey_views.xml
+++ b/addons/survey/views/survey_views.xml
@@ -35,8 +35,7 @@
<field name="state" widget="statusbar"/>
</header>
<sheet>
- <div class="oe_right oe_button_box" name="button_box">
- </div>
+ <div class="oe_button_box" name="button_box"/>
<group col="2">
<group>
<field name="survey_id"/>
@@ -184,11 +183,11 @@
<field name="public_url" />
<templates>
<div t-name="kanban-box" t-attf-class="oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_card oe_kanban_global_click">
- <div class="oe_dropdown_toggle oe_dropdown_kanban" t-if="widget.view.is_action_enabled('edit')">
+ <div class="oe_dropdown_toggle oe_dropdown_kanban" t-if="widget.editable">
<i class="fa fa-bars fa-lg"/>
<ul class="oe_dropdown_menu">
<li><a type="edit">Edit Survey</a></li>
- <li t-if="widget.view.is_action_enabled('delete')"><a type="delete">Delete</a></li>
+ <li t-if="widget.deletable"><a type="delete">Delete</a></li>
<li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
</ul>
</div>
diff --git a/addons/web/static/src/js/framework/core.js b/addons/web/static/src/js/framework/core.js
index 7bd4800ec98..30138102663 100644
--- a/addons/web/static/src/js/framework/core.js
+++ b/addons/web/static/src/js/framework/core.js
@@ -186,6 +186,11 @@ return {
list_widget_registry: new Registry(),
search_widgets_registry: new Registry(),
search_filters_registry: new Registry(),
+
+ // necessary to make the kanban view compatible between
+ // community and enterprise edition
+ one2many_view_registry: new Registry(),
+
};
diff --git a/addons/web/static/src/js/views/form_widgets.js b/addons/web/static/src/js/views/form_widgets.js
index ee04f8376b4..760ea703d35 100644
--- a/addons/web/static/src/js/views/form_widgets.js
+++ b/addons/web/static/src/js/views/form_widgets.js
@@ -285,7 +285,7 @@ var Priority = FieldChar.extend({
},
render_value: function() {
this.priorities = this.prepare_priority();
- this.$el.html(QWeb.render("Priority", {'widget': this}));
+ this.$el.html(QWeb.render("FormPriority", {'widget': this}));
if (!this.get('readonly')){
this.$el.find('li').on('click', this.set_priority.bind(this));
}
@@ -1584,6 +1584,7 @@ var StatInfo = common.AbstractField.extend({
}
}
this.$el.html(QWeb.render("StatInfo", options));
+ this.$el.addClass('o_stat_info');
},
});
diff --git a/addons/web/static/src/js/widgets/pager.js b/addons/web/static/src/js/widgets/pager.js
new file mode 100644
index 00000000000..c195aaf530d
--- /dev/null
+++ b/addons/web/static/src/js/widgets/pager.js
@@ -0,0 +1,111 @@
+odoo.define('web.Pager', function (require) {
+"use strict";
+
+var Widget = require('web.Widget');
+
+var direction = {
+ previous: -1,
+ next: 1,
+};
+
+var Pager = Widget.extend({
+ template: "Pager",
+
+ events: {
+ 'click .o-pager-previous': 'previous',
+ 'click .o-pager-next': 'next',
+ },
+
+ // pager goes from 1 to size (included).
+ // current value is current_min (if limit === 1)
+ // or the interval [current_min, current_min + limit[ if limit > 1
+ init: function (parent, size, current_min, limit, options) {
+ this.state = {
+ size: size,
+ current_min: current_min,
+ limit: limit,
+ };
+ Object.defineProperty(this.state, 'current_max', {
+ get: function() {
+ return Math.min(this.current_min + this.limit - 1, this.size);
+ }
+ });
+ this.options = options || {};
+ this._super(parent);
+ },
+
+ start: function () {
+ this.$content = this.$('.o-pager-value');
+ this._render();
+ return this._super();
+ },
+
+ set_state: function (options) {
+ _.extend(this.state, options);
+ this._render();
+ },
+
+ previous: function(e) {
+ this._change_selection(direction.previous);
+ },
+
+ next: function() {
+ this._change_selection(direction.next);
+ },
+
+ disable: function() {
+ this.$('button').prop("disabled", true);
+ },
+
+ enable: function() {
+ this.$('button').prop("disabled", false);
+ },
+
+ _render: function () {
+ var state;
+ var size = this.state.size;
+ var current_min = this.state.current_min;
+ var current_max = this.state.current_max;
+ var single_page = 1 === current_min && current_max === size;
+
+ if (size === 0 || (single_page && this.options.single_page_hidden)) {
+ this.$el.hide();
+ } else {
+ this.$el.show();
+
+ if (single_page) {
+ this.disable();
+ } else {
+ this.enable();
+ }
+
+ if (this.state.limit === 1) {
+ state = "" + current_min + " / " + size;
+ } else {
+ state = "" + current_min + "-" + current_max + " / " + size;
+ }
+ this.$content.html(state);
+ }
+ },
+
+ _change_selection: function (direction) {
+ var size = this.state.size;
+ var current_min = this.state.current_min;
+ var limit = this.state.limit;
+ current_min = (current_min + limit*direction);
+ if (current_min > size) {
+ current_min = 1;
+ } else if ((current_min < 1) && (limit === 1)) {
+ current_min = size;
+ } else if ((current_min < 1) && (limit > 1)) {
+ current_min = size - ((size % limit) || limit) + 1;
+ }
+ this.state.current_min = current_min;
+ this.trigger('pager_changed', _.clone(this.state));
+ this._render();
+ },
+});
+
+return Pager;
+
+}); \ No newline at end of file
diff --git a/addons/web/static/src/less/enterprise_compatibility.less b/addons/web/static/src/less/enterprise_compatibility.less
new file mode 100644
index 00000000000..1cfd5120c34
--- /dev/null
+++ b/addons/web/static/src/less/enterprise_compatibility.less
@@ -0,0 +1,195 @@
+// ------------------------------------------------------------------
+// Odoo
+// ------------------------------------------------------------------
+
+// This file is necessary to make the community edition of the Odoo web
+// client compatible with the enterprise edition.
+
+// The problem is that we have two web clients in parallel, and every
+// addons should behave properly with both.
+
+@odoo-brand-optional-disabled: #6ED0BC; // Specifically used for status bar status arrows
+@odoo-brand-primary: #337ab7;
+@odoo-brand-optional: @odoo-brand-primary;
+@odoo-brand-secondary: #8f8f8f;
+@odoo-form-group-cols: 12;
+@odoo-horizontal-padding: 16px;
+@odoo-list-grey: #e2e2e0; // FIXME: listview thead background color
+@odoo-main-color-muted: #a8a8a8;
+@odoo-main-text-color: #666666;
+@odoo-webclient-background-color: @odoo-brand-secondary;
+@odoo-view-background-color: red;
+@odoo-shadow-color: #303030;
+@brand-primary: @odoo-brand-primary;
+
+.oe-view-manager {
+ background-color: #f0eeee !important;
+}
+
+.o_kanban_view {
+ background-color: #f0eeee;
+ .o_kanban_header {
+ color: black !important;
+ }
+
+ .o_kanban_config i, .o_kanban_quick_add i {
+ color: #555 !important;
+ &:hover {
+ background-color: darken(#f0eeee, 10%) !important;
+ }
+ }
+
+ .o_column_folded {
+ background-color: #f0eeee !important;
+ border: none !important;
+ span.o_column_title, span.o_column_unfold {
+ // color: white !important;
+ }
+ }
+
+ .o_column_quick_create {
+ background-color: #f0eeee !important;
+ .o_kanban_add_column, .o_kanban_title {
+ color: black !important;
+ }
+
+ }
+}
+
+.oe_list {
+ background-color: white !important;
+}
+
+.btn-icon {
+ .btn-default;
+}
+
+.openerp .oe_avatar {
+ float: left;
+}
+
+.openerp .oe_button_box {
+ float: right;
+}
+
+@grid-gutter-width: 0;
+
+.oe-control-panel .row {
+ margin-left: 15px;
+ margin-right: 15px;
+}
+
+.oe_form_field_one2many {
+ .oe-view-manager {
+ background-color: white;
+
+ .o_kanban_view {
+ background-color: white;
+
+ .o_kanban_record {
+ box-shadow: none;
+ }
+ }
+ }
+}
+
+// Buttons containing only an icon
+.o_icon_button {
+ background-color: transparent;
+ border: 0;
+ padding: 0;
+ outline: none;
+}
+
+// Stars
+.o_priority {
+ display: inline-block;
+ padding: 0;
+ margin: 0;
+ > a {
+ display: inline-block;
+ }
+ .o_star_on, .o_star_off {
+ color: @odoo-main-color-muted !important;
+ &:hover {
+ text-decoration: none;
+ }
+ }
+ .o_star_on {
+ color: gold !important;
+ }
+}
+
+.o_text_overflow {
+ display: block;
+ max-width: 100%;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ vertical-align: top; // To update display context changed by overflow:hidden
+}
+
+.oe-o2m-control-panel {
+ background-color: white;
+}
+
+.oe_formview {
+ .oe_button_box {
+ .oe_stat_button {
+
+ .stat_button_icon {
+ display: inline-block;
+ }
+
+ // padding: @odoo-statbutton-vpadding @odoo-statbutton-spacing @odoo-statbutton-vpadding 0px;
+ text-align: left;
+
+ .o_button_icon {
+ // margin-left: @odoo-statbutton-spacing; // To create the button padding left (firefox bug)
+ display: inline-block;
+ vertical-align: middle;
+ &:before {
+ font-size: x-large;
+ vertical-align: middle;
+ }
+
+ width: 30%;
+ }
+
+ // .o_form_field_percent_pie {
+ // margin-left: @odoo-statbutton-spacing; // To create the button padding left (firefox bug)
+ // }
+
+ .o_stat_info { // contains the value and text
+ display: inline-block;
+ vertical-align: middle;
+
+ max-width: 70%;
+ // padding-right: @odoo-statbutton-spacing;
+ line-height: 1.2;
+
+ .o_stat_value {
+ .o_text_overflow;
+ font-weight: 700;
+ color: @odoo-brand-primary;
+ }
+ .o_stat_text {
+ .o_text_overflow;
+ font-size: small;
+
+ .o_stat_value {
+ display: inline;
+ }
+ }
+ }
+
+
+ // Some buttons only display text and directly use the WidgetButton template instead of StatInfo
+ > span {
+ .o_stat_info; // layout
+ font-size: small;
+ white-space: normal; // text on several lines if needed
+ }
+ }
+ }
+}
diff --git a/addons/web/static/src/less/utils.less b/addons/web/static/src/less/utils.less
new file mode 100644
index 00000000000..8b8d02898e6
--- /dev/null
+++ b/addons/web/static/src/less/utils.less
@@ -0,0 +1,189 @@
+// ------------------------------------------------------------------
+// Margin
+// ------------------------------------------------------------------
+.utils-margin-loop(@index) when (@index < 256) {
+ .o-mt@{index} {margin-top: @index px;}
+ .o-mb@{index} {margin-bottom: @index px;}
+ .o-mr@{index} {margin-right: @index px;}
+ .o-ml@{index} {margin-left: @index px;}
+
+ .utils-margin-loop(@index * 2);
+}
+.utils-margin-loop(2);
+
+// ------------------------------------------------------------------
+// Padding
+// ------------------------------------------------------------------
+.o-webclient-padding(@top: 0px, @right: @odoo-horizontal-padding, @bottom: 0px, @left: @odoo-horizontal-padding) {
+ padding-top: @top;
+ padding-right: @right;
+ padding-bottom: @bottom;
+ padding-left: @left;
+}
+
+// ------------------------------------------------------------------
+// Caret
+// ------------------------------------------------------------------
+.utils-caret-boilerplate() {
+ content: "";
+ display: inline-block;
+ width: 0;
+ height: 0;
+ vertical-align: middle;
+}
+.o-caret-down(@caret-width: @caret-width-base) {
+ .utils-caret-boilerplate;
+ border-bottom: 0;
+ border-left: @caret-width solid transparent;
+ border-right: @caret-width solid transparent;
+ border-top: @caret-width solid;
+ -moz-transform: scale(0.9999); // Smooth the caret on firefox
+}
+.o-caret-up(@caret-width: @caret-width-base) {
+ .utils-caret-boilerplate;
+ border-bottom: @caret-width solid;
+ border-left: @caret-width solid transparent;
+ border-right: @caret-width solid transparent;
+ border-top: 0;
+ -moz-transform: scale(0.9999); // Smooth the caret on firefox
+}
+.o-caret-left(@caret-width: @caret-width-base) {
+ .utils-caret-boilerplate;
+ border-bottom: @caret-width solid transparent;
+ border-left: 0;
+ border-right: @caret-width solid;
+ border-top: @caret-width solid transparent;
+ -moz-transform: scale(0.9999); // Smooth the caret on firefox
+}
+.o-caret-right(@caret-width: @caret-width-base) {
+ .utils-caret-boilerplate;
+ border-bottom: @caret-width solid transparent;
+ border-left: @caret-width solid;
+ border-right: 0;
+ border-top: @caret-width solid transparent;
+ -moz-transform: scale(0.9999); // Smooth the caret on firefox
+}
+
+// ------------------------------------------------------------------
+// Vendor prefixes
+// ------------------------------------------------------------------
+// Flex
+.o-flex-display() {
+ display: -ms-flexbox;
+ display: -moz-box;
+ display: -webkit-box;
+ display: -webkit-flex;
+
+ display: flex;
+}
+.o-inline-flex-display() {
+ display: -ms-inline-flexbox;
+ display: -moz-inline-box;
+ display: -webkit-inline-box;
+ display: -webkit-inline-flex;
+
+ display: inline-flex;
+}
+.o-flex-flow(@direction, @wrap) {
+ -ms-flex-flow: @direction @wrap;
+ -moz-flex-flow: @direction @wrap;
+ -webkit-flex-flow: @direction @wrap;
+
+ flex-flow: @direction @wrap;
+}
+.o-flex(@grow, @schrink, @basis) {
+ -ms-flex: @grow @schrink @basis;
+ -moz-flex: @grow @schrink @basis;
+ -webkit-box-flex: @grow;
+ -webkit-flex: @grow @schrink @basis;
+
+ flex: @grow @schrink @basis;
+}
+.o-justify-content(@justify) {
+ -moz-justify-content: @justify;
+ -webkit-justify-content: @justify;
+
+ justify-content: @justify;
+}
+.o-align-content(@align) {
+ -webkit-align-content: @align;
+
+ align-content: @align;
+}
+.o-align-items(@align) {
+ -webkit-align-items: @align;
+
+ align-items: @align;
+}
+.o-align-self(@align) {
+ -webkit-align-self: @align;
+
+ align-self: @align;
+}
+
+// Background-size
+// https://css-tricks.com/perfect-full-page-background-image/
+.o-background-size(@size) {
+ -webkit-background-size: @size;
+ -moz-background-size: @size;
+ -o-background-size: @size;
+ background-size: @size;
+}
+
+// ------------------------------------------------------------------
+// Dropdowns
+// ------------------------------------------------------------------
+.o-selected-li() {
+ li {
+ position: relative;
+ > a {
+ padding: 3px 25px;
+ color: @odoo-main-text-color;
+ &:hover {
+ color: darken(@odoo-main-text-color, 10%);
+ }
+ }
+ &.selected {
+ > a {
+ color: darken(@odoo-main-text-color, 10%);
+ font-weight: bold;
+ &:before {
+ font-family: FontAwesome;
+ position: absolute;
+ left: 6px;
+ content: "\f00c";
+ }
+ }
+ }
+ }
+}
+
+// ------------------------------------------------------------------
+// Select Appearance
+// ------------------------------------------------------------------
+.o-appearance(@value) {
+ -webkit-appearance: @value;
+ -moz-appearance: @value;
+ appearance: @value;
+}
+
+// ------------------------------------------------------------------
+// Transform
+// ------------------------------------------------------------------
+.o-transform-origin(@x: 50%, @y: 50%, @z: 0) {
+ -ms-transform-origin: @x @y @z;
+ -webkit-transform-origin: @x @y @z;
+ -moz-transform-origin: @x @y @z;
+ transform-origin: @x @y @z;
+}
+
+// ------------------------------------------------------------------
+// Position absolute
+// ------------------------------------------------------------------
+.o-position-absolute(@top: auto, @right: auto, @bottom: auto, @left: auto) {
+ position: absolute;
+ top: @top;
+ left: @left;
+ bottom: @bottom;
+ right: @right;
+} \ No newline at end of file
diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml
index 00406837a47..52a7c8130a6 100644
--- a/addons/web/static/src/xml/base.xml
+++ b/addons/web/static/src/xml/base.xml
@@ -1104,7 +1104,7 @@
</ul>
</div>
</t>
-<t t-name="Priority">
+<t t-name="FormPriority">
<ul style="list-style: none; padding-left: 2px; display: inline-block;">
<t t-foreach="widget.priorities" t-as="rec" >
<li t-att-data-value="rec.click_value" style="display: inline-block;">
@@ -1116,6 +1116,14 @@
</t>
</ul>
</t>
+<t t-name="Priority">
+ <div class="o_priority">
+ <t t-foreach="widget.priorities" t-as="rec" >
+ <a t-if="!widget.get('readonly')" href="#" t-att-data-value="rec.click_value" t-att-title="rec.name" t-att-class="widget.get('value') gte rec.value and 'fa fa-star o_star_on' or 'fa fa-star o_star_off'"/>
+ <span t-if="widget.get('readonly')" t-att-data-value="rec.click_value" t-att-title="rec.name" t-att-class="widget.get('value') gte rec.value and 'fa fa-star o_star_on' or 'fa fa-star o_star_off'"/>
+ </t>
+ </div>
+</t>
<t t-name="FieldEmail">
<span class="oe_form_field oe_form_field_email" t-att-style="widget.node.attrs.style">
<a t-if="widget.get('effective_readonly')" href="#" class="oe_form_uri" target="_blank"/>
@@ -1938,14 +1946,25 @@
<a href="javascript:void(0)"><t t-esc="text"/></a>
</t>
<t t-name="StatInfo">
- <strong><t t-esc="value"/></strong><br/><t t-esc="text"/>
+ <span class="o_stat_value"><t t-esc="value"/></span>
+ <span class="o_stat_text"><t t-esc="text"/></span>
</t>
+
<button t-name="toggle_button" type="button"
t-att-title="widget.string"
style="box-shadow: none; white-space:nowrap;">
<img t-attf-src="#{prefix}/web/static/src/img/icons/#{widget.icon}.png"
t-att-alt="widget.string"/>
</button>
+
+<div t-name="Pager">
+ <span class="o-pager-value"></span>
+ <span class="btn-group btn-group-sm">
+ <button type="button" class="fa fa-chevron-left btn btn-icon o-pager-previous" accesskey="O"/>
+ <button type="button" class="fa fa-chevron-right btn btn-icon o-pager-next" accesskey="P"/>
+ </span>
+</div>
+
<button t-name="FieldToggleBoolean" type="button"
t-att-title="widget.string" class="oe_toggle_button">
<img t-attf-src="#{_s}/web/static/src/img/icons/#{widget.icon}" t-att-alt="widget.string"/>
diff --git a/addons/web/views/webclient_templates.xml b/addons/web/views/webclient_templates.xml
index 3b935733230..b99979f2b04 100644
--- a/addons/web/views/webclient_templates.xml
+++ b/addons/web/views/webclient_templates.xml
@@ -73,6 +73,8 @@
<script type="text/javascript" src="/web/static/lib/select2/select2.js"></script>
<link rel="stylesheet" href='/website/static/src/less/import_bootstrap.less'/>
+ <link rel="stylesheet" href="/web/static/src/less/enterprise_compatibility.less"/>
+ <link rel="stylesheet" href="/web/static/src/less/utils.less"/>
<script src="/web/static/lib/bootstrap/js/affix.js"></script>
<script src="/web/static/lib/bootstrap/js/alert.js"></script>
<script src="/web/static/lib/bootstrap/js/button.js"></script>
@@ -138,6 +140,7 @@
<script type="text/javascript" src="/web/static/src/js/widgets/notification.js"></script>
<script type="text/javascript" src="/web/static/src/js/widgets/sidebar.js"></script>
<script type="text/javascript" src="/web/static/src/js/widgets/progress_bar.js"></script>
+ <script type="text/javascript" src="/web/static/src/js/widgets/pager.js"></script>
<script type="text/javascript" src="/web/static/src/js/widgets/systray_menu.js"></script>
<script type="text/javascript" src="/web/static/src/js/widgets/user_menu.js"></script>
<script type="text/javascript" src="/web/static/src/js/framework/dialog.js"></script>
diff --git a/addons/web_kanban/static/src/css/kanban.css b/addons/web_kanban/static/src/css/kanban.css
index 840597606dd..494fe5b10c6 100644
--- a/addons/web_kanban/static/src/css/kanban.css
+++ b/addons/web_kanban/static/src/css/kanban.css
@@ -577,11 +577,11 @@
background: #ffffff;
}
-.openerp .oe_popup_form .oe_kanban_buttons .oe_highlight {
+.openerp .o_popup_form .oe_kanban_buttons .oe_highlight {
color: #404040;
background: none;
}
-.openerp .oe_popup_form .oe_kanban_buttons button.oe_highlight {
+.openerp .o_popup_form .oe_kanban_buttons button.oe_highlight {
background-color: #efefef;
background-image: -webkit-gradient(linear, left top, left bottom, from(#efefef), to(#d8d8d8));
background-image: -webkit-linear-gradient(top, #efefef, #d8d8d8);
@@ -593,7 +593,7 @@
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset;
-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset;
}
-.openerp .oe_popup_form .oe_kanban_buttons button.oe_highlight:active {
+.openerp .o_popup_form .oe_kanban_buttons button.oe_highlight:active {
background-color: #e3e3e3;
background-image: -webkit-gradient(linear, left top, left bottom, from(#e3e3e3), to(#f6f6f6));
background-image: -webkit-linear-gradient(top, #e3e3e3, #f6f6f6);
@@ -605,7 +605,7 @@
-webkit-box-shadow: none;
-box-shadow: none;
}
-.openerp .oe_popup_form .oe_kanban_buttons button.oe_highlight:hover {
+.openerp .o_popup_form .oe_kanban_buttons button.oe_highlight:hover {
background-color: #f6f6f6;
background-image: -webkit-gradient(linear, left top, left bottom, from(#f6f6f6), to(#e3e3e3));
background-image: -webkit-linear-gradient(top, #f6f6f6, #e3e3e3);
diff --git a/addons/web_kanban/static/src/css/kanban.sass b/addons/web_kanban/static/src/css/kanban.sass
index b229c8c9d41..5b7d187d9a1 100644
--- a/addons/web_kanban/static/src/css/kanban.sass
+++ b/addons/web_kanban/static/src/css/kanban.sass
@@ -514,7 +514,7 @@
padding: 0px
background: #ffffff
.openerp
- .oe_popup_form
+ .o_popup_form
.oe_kanban_buttons
.oe_highlight
color: #404040
diff --git a/addons/web_kanban/static/src/js/compatibility.js b/addons/web_kanban/static/src/js/compatibility.js
index 256086b9ef1..a8ecd06f8d6 100644
--- a/addons/web_kanban/static/src/js/compatibility.js
+++ b/addons/web_kanban/static/src/js/compatibility.js
@@ -1,15 +1,17 @@
odoo.define('web_kanban.compatibility', function (require) {
"use strict";
-var common = require('web_kanban.common');
+var kanban_widgets = require('web_kanban.widgets');
+var KanbanRecord = require('web_kanban.Record');
+var KanbanColumn = require('web_kanban.Column');
var KanbanView = require('web_kanban.KanbanView');
return;
openerp = window.openerp || {};
openerp.web_kanban = openerp.web_kanban || {};
-openerp.web_kanban.AbstractField = common.AbstractField;
-openerp.web_kanban.KanbanGroup = common.KanbanGroup;
-openerp.web_kanban.KanbanRecord = common.KanbanRecord;
+openerp.web_kanban.AbstractField = kanban_widgets.AbstractField;
+openerp.web_kanban.KanbanGroup = KanbanColumn;
+openerp.web_kanban.KanbanRecord = KanbanRecord;
openerp.web_kanban.KanbanView = KanbanView;
});
diff --git a/addons/web_kanban/static/src/js/kanban_column.js b/addons/web_kanban/static/src/js/kanban_column.js
new file mode 100644
index 00000000000..85333ffbe3f
--- /dev/null
+++ b/addons/web_kanban/static/src/js/kanban_column.js
@@ -0,0 +1,245 @@
+odoo.define('web_kanban.Column', function (require) {
+"use strict";
+
+var core = require('web.core');
+var Dialog = require('web.Dialog');
+var form_common = require('web.form_common');
+var Widget = require('web.Widget');
+var quick_create = require('web_kanban.quick_create');
+var KanbanRecord = require('web_kanban.Record');
+
+var _t = core._t;
+var QWeb = core.qweb;
+var RecordQuickCreate = quick_create.RecordQuickCreate;
+
+var KanbanColumn = Widget.extend({
+ template: "KanbanView.Group",
+
+ events: {
+ 'click .o_kanban_toggle_fold': function (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ this.folded = true;
+ this.update_column();
+ },
+ 'click .o_column_edit': 'edit_column',
+ 'click .o_column_delete': 'delete_column',
+ 'click .o_kanban_quick_add': 'add_quick_create',
+ 'click .o_kanban_load_more': 'load_more',
+ },
+
+ custom_events: {
+ 'kanban_record_delete': 'delete_record',
+ 'cancel_quick_create': 'cancel_quick_create',
+ 'quick_create_add_record': 'quick_create_add_record',
+ },
+
+ init: function(parent, group_data, options, record_options) {
+ this._super(parent);
+ this.data_records = group_data.records;
+ this.dataset = group_data.dataset;
+ this.records = [];
+ this.title = group_data.title;
+ this.id = group_data.id;
+ this.folded = group_data.attributes.folded;
+ this.fields = options.fields;
+ this.values = group_data.values;
+
+ this.quick_create = options.quick_create;
+ this.grouped_by_m2o = options.grouped_by_m2o;
+ this.editable = options.editable;
+ this.deletable = options.deletable;
+ this.records_editable = options.records_editable;
+ this.records_deletable = options.records_deletable;
+ this.relation = options.relation;
+ this.offset = 0;
+ this.remaining = this.dataset.size() - this.data_records.length;
+
+ this.record_options = _.extend(_.clone(record_options), {
+ group_info: this.values,
+ });
+ },
+
+ start: function() {
+ var self = this;
+ this.$header = this.$('.o_kanban_header');
+
+ for (var i = 0; i < this.data_records.length; i++) {
+ this.add_record(this.data_records[i], {no_update: true});
+ }
+ this.$header.tooltip();
+
+ this.update_column();
+ this.$el.sortable({
+ connectWith: '.o_kanban_group',
+ revert: 150,
+ delay: 100,
+ items: '> .o_kanban_record',
+ helper: 'clone',
+ cursor: 'move',
+ over: function () {
+ self.folded = false;
+ self.update_column();
+ },
+ update: function (event, ui) {
+ var record = ui.item.data('record');
+ var index = self.records.indexOf(record);
+ var test2 = $.contains(self.$el[0], record.$el[0]);
+ if (index >= 0 && test2) {
+ // resequencing records
+ record.$el.removeAttr('style'); // jqueryui sortable add display:block inline
+ self.trigger_up('kanban_column_resequence');
+ } else if (index >= 0 && !test2) {
+ // removing record from this column
+ self.records.splice(self.records.indexOf(record), 1);
+ self.dataset.remove_ids([record.id]);
+ } else {
+ // adding record to this column
+ self.records.push(record);
+ record.setParent(self);
+ self.trigger_up('kanban_column_add_record', {record: record});
+ }
+ self.update_column();
+ }
+ });
+ this.$el.click(function (event) {
+ if (self.$el.hasClass('o_column_folded')) {
+ event.preventDefault();
+ self.folded = false;
+ self.update_column();
+ }
+ });
+ },
+
+ is_empty: function () {
+ return !this.records.length;
+ },
+
+ add_record: function (data, options) {
+ var record = new KanbanRecord(this, data, this.record_options);
+ this.records.push(record);
+ this.dataset.ids = _.uniq(this.dataset.ids.concat(record.id));
+ if (options.position === 'before') {
+ record.insertAfter(this.quick_create_widget ? this.quick_create_widget.$el : this.$header);
+ } else {
+ var $load_more = this.$('.o_kanban_load_more');
+ if ($load_more.length) {
+ record.insertBefore($load_more);
+ } else {
+ record.appendTo(this.$el);
+ }
+ }
+ if (!options.no_update) {
+ this.update_column();
+ }
+ },
+
+ get_ids: function () {
+ var ids = [];
+ this.$('.o_kanban_record').each(function (index, r) {
+ ids.push($(r).data('record').id);
+ });
+ return ids;
+ },
+
+ update_column: function () {
+ var title = this.folded ? this.title + ' (' + this.records.length + ')' : this.title;
+ this.$header.find('.o_column_title').text(title);
+ this.$header.find('.o-kanban-count').text(this.records.length);
+
+ this.$el.toggleClass('o_column_folded', this.folded);
+ var tooltip;
+ if (this.remaining) {
+ tooltip = this.records.length + '/' + this.dataset.size() + _t(' records');
+ } else {
+ tooltip = this.records.length + _t(' records');
+ }
+ this.$header.tooltip().attr('data-original-title', tooltip);
+ if (!this.remaining) {
+ this.$('.o_kanban_load_more').remove();
+ } else {
+ this.$('.o_kanban_load_more').html(QWeb.render('KanbanView.LoadMore', {widget:this}))
+ }
+ },
+
+ delete_column: function (event) {
+ event.preventDefault();
+ var buttons = [
+ {
+ text: _t("Ok"),
+ classes: 'btn-primary',
+ close: true,
+ click: this.trigger_up.bind(this, 'kanban_column_delete')
+ },
+ {text: _t("Cancel"), close: true}
+ ];
+ new Dialog(this, {
+ size: 'medium',
+ buttons: buttons,
+ $content: $('<div>', {
+ text: _t("Are you sure that you want to remove this column ?")
+ }),
+ }).open();
+ },
+
+ edit_column: function (event) {
+ event.preventDefault();
+ var dialog = new form_common.FormViewDialog(this, {
+ res_model: this.relation,
+ res_id: this.id,
+ title: _t("Edit Column"),
+ }).open();
+
+ dialog.on('record_saved', this, function () {
+ this.trigger_up('kanban_reload');
+ });
+ },
+
+ delete_record: function (event) {
+ event.stopped = false;
+ var self = this;
+ event.data.after = function cleanup () {
+ var index = self.records.indexOf(event.data.record);
+ self.records.splice(index, 1);
+ self.update_column();
+ };
+ },
+
+ add_quick_create: function () {
+ if (this.quick_create_widget) {
+ return;
+ }
+ var self = this;
+ var width = this.records.length ? this.records[0].$el.innerWidth() : this.$el.width() - 8;
+ this.quick_create_widget = new RecordQuickCreate(this, width);
+ this.quick_create_widget.insertAfter(this.$header);
+ this.quick_create_widget.$el.focusout(function () {
+ setTimeout(function() {
+ var hasFocus = !! (self.quick_create_widget.$(':focus').length > 0);
+ if (! hasFocus && self.quick_create_widget) {
+ self.cancel_quick_create();
+ }
+ }, 10);
+ });
+
+ },
+
+ cancel_quick_create: function () {
+ this.quick_create_widget.destroy();
+ this.quick_create_widget = undefined;
+ },
+
+ quick_create_add_record: function (event) {
+ this.trigger_up('column_add_record', event.data);
+ },
+
+ load_more: function (event) {
+ event.preventDefault();
+ this.trigger_up('kanban_load_more');
+ },
+
+});
+
+return KanbanColumn;
+
+});
diff --git a/addons/web_kanban/static/src/js/kanban_common.js b/addons/web_kanban/static/src/js/kanban_common.js
deleted file mode 100644
index b63758aaa28..00000000000
--- a/addons/web_kanban/static/src/js/kanban_common.js
+++ /dev/null
@@ -1,928 +0,0 @@
-odoo.define('web_kanban.common', function (require) {
-"use strict";
-
-var core = require('web.core');
-var data = require('web.data');
-var form_common = require('web.form_common');
-var formats = require('web.formats');
-var framework = require('web.framework');
-var ProgressBar = require('web.ProgressBar');
-var pyeval = require('web.pyeval');
-var Registry = require('web.Registry');
-var session = require('web.session');
-var time = require('web.time');
-var utils = require('web.utils');
-var web_client = require('web.web_client');
-var Widget = require('web.Widget');
-
-var QWeb = core.qweb;
-var _t = core._t;
-/**
- * Interface to be implemented by kanban fields.
- *
- */
-var FieldInterface = {
- /**
- Constructor.
- - parent: The widget's parent.
- - field: A dictionary giving details about the field, including the current field's value in the
- raw_value field.
- - $node: The field <field> tag as it appears in the view, encapsulated in a jQuery object.
- */
- init: function(parent, field, $node) {},
-};
-
-/**
- * Abstract class for classes implementing FieldInterface.
- *
- * Properties:
- * - value: useful property to hold the value of the field. By default, the constructor
- * sets value property.
- *
- */
-var AbstractField = Widget.extend(FieldInterface, {
- /**
- Constructor that saves the field and $node parameters and sets the "value" property.
- */
- init: function(parent, field, $node) {
- this._super(parent);
- this.field = field;
- this.$node = $node;
- this.options = pyeval.py_eval(this.$node.attr("options") || '{}');
- this.set("value", field.raw_value);
- },
-});
-
-var Priority = AbstractField.extend({
- init: function(parent, field, $node) {
- this._super.apply(this, arguments);
- this.name = $node.attr('name');
- this.parent = parent;
- },
- prepare_priority: function() {
- var self = this;
- var selection = this.field.selection || [];
- var init_value = selection && selection[0][0] || 0;
- var data = _.map(selection.slice(1), function(element, index) {
- var value = {
- 'value': element[0],
- 'name': element[1],
- 'click_value': element[0],
- };
- if (index === 0 && self.get('value') == element[0]) {
- value.click_value = init_value;
- }
- return value;
- });
- return data;
- },
- renderElement: function() {
- this.record_id = this.parent.id;
- this.priorities = this.prepare_priority();
- var readonly = this.field && this.field.readonly;
- if (readonly){
- this.set('readonly', true);
- }
- this.$el = $(QWeb.render("Priority", {'widget': this}));
- if (!readonly){
- this.$el.find('li').click(this.do_action.bind(this));
- }
- },
- do_action: function(e) {
- var self = this;
- var li = $(e.target).closest( "li" );
- if (li.length) {
- var value = {};
- value[self.name] = String(li.data('value'));
- return self.parent.view.dataset._model.call('write', [[self.record_id], value, self.parent.view.dataset.get_context()]).done(self.reload_record.bind(self.parent));
- }
- },
- reload_record: function() {
- this.do_reload();
- },
-});
-
-var KanbanSelection = AbstractField.extend({
- init: function(parent, field, $node) {
- this._super.apply(this, arguments);
- this.name = $node.attr('name');
- this.parent = parent;
- },
- prepare_dropdown_selection: function() {
- var self = this;
- var data = [];
- _.map(this.field.selection || [], function(res) {
- var value = {
- 'name': res[0],
- 'tooltip': res[1],
- 'state_name': res[1],
- };
- var leg_opt = self.options && self.options.states_legend || null;
- if (leg_opt && leg_opt[res[0]] && self.parent.group.values && self.parent.group.values[leg_opt[res[0]]]) {
- value['state_name'] = self.parent.group.values[leg_opt[res[0]]];
- value['tooltip'] = self.parent.group.values[leg_opt[res[0]]];
- }
- if (res[0] == 'normal') { value['state_class'] = 'oe_kanban_status'; }
- else if (res[0] == 'done') { value['state_class'] = 'oe_kanban_status oe_kanban_status_green'; }
- else { value['state_class'] = 'oe_kanban_status oe_kanban_status_red'; }
- data.push(value);
- });
- return data;
- },
- renderElement: function() {
- var self = this;
- this.record_id = self.parent.id;
- this.states = self.prepare_dropdown_selection();
- this.$el = $(QWeb.render("KanbanSelection", {'widget': self}));
- this.$el.find('li').click(self.do_action.bind(self));
- },
- do_action: function(e) {
- var self = this;
- var li = $(e.target).closest( "li" );
- if (li.length) {
- var value = {};
- value[self.name] = String(li.data('value'));
- return self.parent.view.dataset._model.call('write', [[self.record_id], value, self.parent.view.dataset.get_context()]).done(self.reload_record.bind(self.parent));
- }
- },
- reload_record: function() {
- this.do_reload();
- },
-});
-
-
-/**
- * Quick creation view.
- *
- * Triggers a single event "added" with a single parameter "name", which is the
- * name entered by the user
- *
- * @class
- * @type {*}
- */
-var QuickCreate = Widget.extend({
- template: 'KanbanView.quick_create',
-
- /**
- * close_btn: If true, the widget will display a "Close" button able to trigger
- * a "close" event.
- */
- init: function(parent, dataset, context, buttons) {
- this._super(parent);
- this._dataset = dataset;
- this._buttons = buttons || false;
- this._context = context || {};
- },
- start: function () {
- var self = this;
- self.$input = this.$el.find('input');
- self.$input.keyup(function(event){
- if(event.keyCode == 13){
- self.quick_add();
- }
- });
- $(".oe_kanban_quick_create").focusout(function (e) {
- var val = self.$el.find('input').val();
- if (/^\s*$/.test(val)) { self.trigger('close'); }
- e.stopImmediatePropagation();
- });
- $(".oe_kanban_quick_create_add", this.$el).click(function () {
- self.quick_add();
- self.focus();
- });
- $(".oe_kanban_quick_create_close", this.$el).click(function (ev) {
- ev.preventDefault();
- self.trigger('close');
- });
- self.$input.keyup(function(e) {
- if (e.keyCode == 27 && self._buttons) {
- self.trigger('close');
- }
- });
- },
- focus: function() {
- this.$el.find('input').focus();
- },
- /**
- * Handles user event from nested quick creation view
- */
- quick_add: function () {
- var self = this;
- var val = this.$input.val();
- if (/^\s*$/.test(val)) { this.$el.remove(); return; }
- this._dataset.call(
- 'name_create', [val, new data.CompoundContext(
- this._dataset.get_context(), this._context)])
- .then(function(record) {
- self.$input.val("");
- self.trigger('added', record[0]);
- }, function(error, event) {
- event.preventDefault();
- return self.slow_create();
- });
- },
- slow_create: function() {
- var self = this;
- var popup = new form_common.SelectCreatePopup(this);
- popup.select_element(
- self._dataset.model,
- {
- title: _t("Create: ") + (this.string || this.name),
- initial_view: "form",
- disable_multiple_selection: true
- },
- [],
- {"default_name": self.$input.val()}
- );
- popup.on("elements_selected", self, function(element_ids) {
- self.$input.val("");
- self.trigger('added', element_ids[0]);
- });
- }
-});
-
-var KanbanRecord = Widget.extend({
- template: 'KanbanView.record',
-
- events: {
- 'click .o_kanban_manage_toggle_button': 'toggle_manage_pane',
- },
-
- init: function (parent, record) {
- this._super(parent);
- this.group = parent;
- this.view = parent.view;
- this.id = null;
- this.set_record(record);
- if (!this.view.state.records[this.id]) {
- this.view.state.records[this.id] = {
- folded: false
- };
- }
- this.state = this.view.state.records[this.id];
- this.fields = {};
- },
- set_record: function(record) {
- var self = this;
- this.id = record.id;
- this.values = {};
- _.each(record, function(v, k) {
- self.values[k] = {
- value: v
- };
- });
- this.record = this.transform_record(record);
- },
- start: function() {
- var self = this;
- this._super();
- this.init_content();
- },
- init_content: function() {
- var self = this;
- self.sub_widgets = [];
- this.$("[data-field_id]").each(function() {
- self.add_widget($(this));
- });
- this.$el.data('widget', this);
- this.bind_events();
- },
- transform_record: function(record) {
- var self = this,
- new_record = {};
- _.each(record, function(value, name) {
- var r = _.clone(self.view.fields_view.fields[name] || {});
- if ((r.type === 'date' || r.type === 'datetime') && value) {
- r.raw_value = time.auto_str_to_date(value);
- } else {
- r.raw_value = value;
- }
- r.value = formats.format_value(value, r);
- new_record[name] = r;
- });
- return new_record;
- },
- renderElement: function() {
- this.qweb_context = {
- record: this.record,
- widget: this,
- read_only_mode: this.view.options.read_only_mode,
- };
- for (var p in this) {
- if (_.str.startsWith(p, 'kanban_')) {
- this.qweb_context[p] = _.bind(this[p], this);
- }
- }
- var $el = QWeb.render(this.template, {
- 'widget': this,
- 'content': this.view.qweb.render('kanban-box', this.qweb_context)
- });
- this.replaceElement($el);
- this.replace_fields();
- },
- replace_fields: function() {
- var self = this;
- this.$("field").each(function() {
- var $field = $(this);
- var $nfield = $("<span></span");
- var id = _.uniqueId("kanbanfield");
- self.fields[id] = $field;
- $nfield.attr("data-field_id", id);
- $field.replaceWith($nfield);
- });
- },
- add_widget: function($node) {
- var $orig = this.fields[$node.data("field_id")];
- var field = this.record[$orig.attr("name")];
- var type = field.type;
- type = $orig.attr("widget") ? $orig.attr("widget") : type;
- var obj = fields_registry.get(type);
- var widget = new obj(this, field, $orig);
- this.sub_widgets.push(widget);
- widget.replace($node);
- },
- bind_events: function() {
- var self = this;
- this.setup_color_picker();
- this.$el.find('[title]').each(function(){
- $(this).tooltip({
- delay: { show: 500, hide: 0},
- title: function() {
- var template = $(this).attr('tooltip');
- if (!self.view.qweb.has_template(template)) {
- return false;
- }
- return self.view.qweb.render(template, self.qweb_context);
- },
- });
- });
-
- // If no draghandle is found, make the whole card as draghandle (provided one can edit)
- if (!this.$el.find('.oe_kanban_draghandle').length) {
- this.$el.children(':first')
- .toggleClass('oe_kanban_draghandle', this.view.is_action_enabled('edit'));
- }
-
- this.$el.find('.oe_kanban_action').click(function(ev) {
- ev.preventDefault();
- var $action = $(this),
- type = $action.data('type') || 'button',
- method = 'do_action_' + (type === 'action' ? 'object' : type);
- if ((type === 'edit' || type === 'delete') && ! self.view.is_action_enabled(type)) {
- self.view.open_record(self.id, true);
- } else if (_.str.startsWith(type, 'switch_')) {
- self.view.do_switch_view(type.substr(7));
- } else if (typeof self[method] === 'function') {
- self[method]($action);
- } else {
- self.do_warn("Kanban: no action for type : " + type);
- }
- });
-
- if (this.$el.find('.oe_kanban_global_click,.oe_kanban_global_click_edit').length) {
- this.$el.on('click', function(ev) {
- if (!ev.isTrigger && !$._data(ev.target, 'events')) {
- var trigger = true;
- var elem = ev.target;
- var ischild = true;
- var children = [];
- while (elem) {
- var events = $._data(elem, 'events');
- if (elem == ev.currentTarget) {
- ischild = false;
- }
- if (ischild) {
- children.push(elem);
- if (events && events.click) {
- // do not trigger global click if one child has a click event registered
- trigger = false;
- }
- }
- if (trigger && events && events.click) {
- _.each(events.click, function(click_event) {
- if (click_event.selector) {
- // For each parent of original target, check if a
- // delegated click is bound to any previously found children
- _.each(children, function(child) {
- if ($(child).is(click_event.selector)) {
- trigger = false;
- }
- });
- }
- });
- }
- elem = elem.parentElement;
- }
- if (trigger) {
- self.on_card_clicked(ev);
- }
- }
- });
- }
- },
- /* actions when user click on the block with a specific class
- * open on normal view : oe_kanban_global_click
- * open on form/edit view : oe_kanban_global_click_edit
- */
- on_card_clicked: function(ev) {
- if (this.$el.find('.oe_kanban_global_click').size() > 0 && this.$el.find('.oe_kanban_global_click').data('routing')) {
- framework.redirect(this.$el.find('.oe_kanban_global_click').data('routing') + "/" + this.id);
- }
- else if (this.$el.find('.oe_kanban_global_click_edit').size()>0)
- this.do_action_edit();
- else
- this.do_action_open();
- },
- setup_color_picker: function() {
- var self = this;
- var $el = this.$el.find('ul.oe_kanban_colorpicker');
- if ($el.length) {
- $el.html(QWeb.render('KanbanColorPicker', {
- widget: this
- }));
- $el.on('click', 'a', function(ev) {
- ev.preventDefault();
- var color_field = $(this).parents('.oe_kanban_colorpicker').first().data('field') || 'color';
- var data = {};
- data[color_field] = $(this).data('color');
- self.view.dataset.write(self.id, data, {}).done(function() {
- self.record[color_field] = $(this).data('color');
- self.do_reload();
- });
- });
- }
- },
- toggle_manage_pane: function(){
- this.$('.o_kanban_card_content').toggleClass('o_visible o_invisible');
- this.$('.o_kanban_card_manage_pane').toggleClass('o_visible o_invisible');
- this.$('.o_kanban_manage_button_section').toggleClass(this.kanban_color((this.values['color'] && this.values['color'].value) || 0));
- },
-
- do_action_delete: function($action) {
- var self = this;
- function do_it() {
- return $.when(self.view.dataset.unlink([self.id])).done(function() {
- self.group.remove_record(self.id);
- self.destroy();
- });
- }
- if (this.view.options.confirm_on_delete) {
- if (confirm(_t("Are you sure you want to delete this record ?"))) {
- return do_it();
- }
- } else
- return do_it();
- },
- do_action_edit: function($action) {
- this.view.open_record(this.id, true);
- },
- do_action_open: function($action) {
- this.view.open_record(this.id);
- },
- do_action_object: function ($action) {
- var button_attrs = $action.data();
- var node_context = button_attrs.context || {};
- var context = new data.CompoundContext(node_context);
- context.set_eval_context({
- active_id: this.id,
- active_ids: [this.id],
- active_model: this.view.dataset.model
- });
- var action_data = _.extend({}, button_attrs, {context: context});
- this.view.do_execute_action(action_data, this.view.dataset, this.id, this.do_reload);
- },
- do_action_url: function($action) {
- return framework.redirect($action.attr("href"));
- },
- do_reload: function() {
- var self = this;
- this.view.dataset.read_ids([this.id], this.view.fields_keys.concat(['__last_update'])).done(function(records) {
- _.each(self.sub_widgets, function(el) {
- el.destroy();
- });
- self.sub_widgets = [];
- if (records.length) {
- self.set_record(records[0]);
- self.renderElement();
- self.init_content();
- self.group.compute_cards_auto_height();
- self.view.postprocess_m2m_tags();
- } else {
- self.destroy();
- }
- });
- },
- kanban_getcolor: function(variable) {
- var index = 0;
- switch (typeof(variable)) {
- case 'string':
- for (var i=0, ii=variable.length; i<ii; i++) {
- index += variable.charCodeAt(i);
- }
- break;
- case 'number':
- index = Math.round(variable);
- break;
- default:
- return '';
- }
- var color = (index % this.view.number_of_color_schemes);
- return color;
- },
- kanban_color: function(variable) {
- var color = this.kanban_getcolor(variable);
- return color === '' ? '' : 'oe_kanban_color_' + color;
- },
- kanban_image: function(model, field, id, cache, options) {
- options = options || {};
- var url;
- if (this.record[field] && this.record[field].value && !utils.is_bin_size(this.record[field].value)) {
- url = 'data:image/png;base64,' + this.record[field].value;
- } else if (this.record[field] && ! this.record[field].value) {
- url = "/web/static/src/img/placeholder.png";
- } else {
- id = JSON.stringify(id);
- if (options.preview_image)
- field = options.preview_image;
- url = session.url('/web/binary/image', {model: model, field: field, id: id});
- if (cache !== undefined) {
- // Set the cache duration in seconds.
- url += '&cache=' + parseInt(cache, 10);
- }
- }
- return url;
- },
- kanban_text_ellipsis: function(s, size) {
- size = size || 160;
- if (!s) {
- return '';
- } else if (s.length <= size) {
- return s;
- } else {
- return s.substr(0, size) + '...';
- }
- },
- kanban_compute_domain: function(domain) {
- return data.compute_domain(domain, this.values);
- }
-});
-
-
-var KanbanGroup = Widget.extend({
- template: 'KanbanView.group_header',
- init: function (parent, records, group, dataset) {
- var self = this;
- this._super(parent);
- this.$has_been_started = $.Deferred();
- this.view = parent;
- this.group = group;
- this.dataset = dataset;
- this.dataset_offset = 0;
- this.value = this.title = this.values = null;
- if (this.group) {
- this.values = group.values;
- this.value = group.get('value');
- this.title = group.get('value');
- if (this.value instanceof Array) {
- this.title = this.value[1];
- this.value = this.value[0];
- }
- var field = this.view.group_by_field;
- if (!_.isEmpty(field)) {
- try {
- this.title = formats.format_value(group.get('value'), field, false);
- } catch(e) {}
- }
- }
-
- if (this.title === false) {
- this.title = _t('Undefined');
- this.undefined_title = true;
- }
- var key = this.view.group_by + '-' + this.value;
- if (!this.view.state.groups[key]) {
- this.view.state.groups[key] = {
- folded: group ? group.get('folded') : false
- };
- }
- this.state = this.view.state.groups[key];
- this.$records = null;
-
- this.records = [];
- this.$has_been_started.done(function() {
- self.do_add_records(records);
- });
- },
- start: function() {
- var self = this,
- def = this._super();
- if (! self.view.group_by) {
- self.$el.addClass("oe_kanban_no_group");
- var QuickCreateClass = self.view.get_quick_create_class();
- self.quick = (new QuickCreateClass(this, self.dataset, {}, false))
- .on('added', self, self.proxy('quick_created'));
- self.quick.replace($(".oe_kanban_no_group_qc_placeholder"));
- }
- this.$records = $(QWeb.render('KanbanView.group_records_container', { widget : this}));
- this.$records.insertBefore(this.view.$el.find('.oe_kanban_groups_records td:last'));
-
- this.$el.on('click', '.oe_kanban_group_dropdown li a', function(ev) {
- var fn = 'do_action_' + $(ev.target).data().action;
- if (typeof(self[fn]) === 'function') {
- self[fn]($(ev.target));
- }
- });
-
- this.$el.find('.oe_kanban_add').click(function () {
- if (self.view.quick) {
- self.view.quick.trigger('close');
- }
- if (self.quick) {
- return false;
- }
- self.view.$el.find('.oe_view_nocontent').hide();
- var ctx = {};
- ctx['default_' + self.view.group_by] = self.value;
- self.quick = new (self.view.get_quick_create_class())(this, self.dataset, ctx, true)
- .on('added', self, self.proxy('quick_created'))
- .on('close', self, function() {
- self.view.$el.find('.oe_view_nocontent').show();
- this.quick.destroy();
- delete self.view.quick;
- delete this.quick;
- });
- self.quick.appendTo($(".oe_kanban_group_list_header", self.$records));
- self.quick.focus();
- self.view.quick = self.quick;
- });
- // Add bounce effect on image '+' of kanban header when click on empty space of kanban grouped column.
- this.$records.on('click', '.oe_kanban_show_more', this.do_show_more);
- if (this.state.folded) {
- this.do_toggle_fold();
- }
- this.$el.data('widget', this);
- this.$records.data('widget', this);
- this.$has_been_started.resolve();
- var add_btn = this.$el.find('.oe_kanban_add');
- add_btn.tooltip({delay: { show: 500, hide:1000 }});
- this.$records.find(".oe_kanban_column_cards").click(function (ev) {
- if (ev.target == ev.currentTarget) {
- if (!self.state.folded) {
- add_btn.openerpBounce();
- }
- }
- });
- this.is_started = true;
- this.fetch_tooltip();
- return def;
- },
- /*
- * Form the tooltip, based on optional group_by_tooltip on the grouping field.
- * This function goes through the arch of the view, finding the declaration
- * of the field used to group. If group_by_tooltip is defined, use the previously
- * computed values of the group to form the tooltip. */
- fetch_tooltip: function() {
- var self = this;
- if (! this.group)
- return;
- var options = null;
- var recurse = function(node) {
- if (node.tag === "field" && node.attrs.name == self.view.group_by) {
- options = pyeval.py_eval(node.attrs.options || '{}');
- return;
- }
- _.each(node.children, function(child) {
- recurse(child);
- });
- };
- recurse(this.view.fields_view.arch);
- if (options && options.group_by_tooltip) {
- this.tooltip = _.compact(
- _.union(
- [this.title],
- _.map(
- options.group_by_tooltip,
- function (key, value, list) { return self.values && self.values[value] && (key + "\n" + self.values[value]) || ''; }))
- ).join('\n\n');
- this.$(".oe_kanban_group_title_text").attr("title", this.tooltip || this.title || "");
- }
- },
- compute_cards_auto_height: function() {
- // oe_kanban_no_auto_height is an empty class used to disable this feature
- if (!this.view.group_by) {
- var min_height = 0;
- var els = [];
- _.each(this.records, function(r) {
- var $e = r.$el.children(':first:not(.oe_kanban_no_auto_height)').css('min-height', 0);
- if ($e.length) {
- els.push($e[0]);
- min_height = Math.max(min_height, $e.outerHeight());
- }
- });
- $(els).css('min-height', min_height);
- }
- },
- destroy: function() {
- this._super();
- if (this.$records) {
- this.$records.remove();
- }
- },
- do_show_more: function(evt) {
- var self = this;
- var ids = self.view.dataset.ids.slice(0);
- return this.dataset.read_slice(this.view.fields_keys.concat(['__last_update']), {
- 'limit': self.view.limit,
- 'offset': self.dataset_offset += self.view.limit
- }).then(function(records) {
- self.view.dataset.ids = ids.concat(_.difference(self.dataset.ids, ids));
- self.do_add_records(records);
- self.compute_cards_auto_height();
- self.view.postprocess_m2m_tags();
- return records;
- });
- },
- do_add_records: function(records, prepend) {
- var self = this;
- var $list_header = this.$records.find('.oe_kanban_group_list_header');
- var $show_more = this.$records.find('.oe_kanban_show_more');
- var $cards = this.$records.find('.oe_kanban_column_cards');
-
- _.each(records, function(record) {
- var rec = new KanbanRecord(self, record);
- if (!prepend) {
- rec.appendTo($cards);
- self.records.push(rec);
- } else {
- rec.prependTo($cards);
- self.records.unshift(rec);
- }
- });
- if ($show_more.length) {
- var size = this.dataset.size();
- $show_more.toggle(this.records.length < size).find('.oe_kanban_remaining').text(size - this.records.length);
- }
- },
- remove_record: function(id, remove_from_dataset) {
- for (var i = 0; i < this.records.length; i++) {
- if (this.records[i]['id'] === id) {
- this.records.splice(i, 1);
- i--;
- }
- }
- },
- do_toggle_fold: function(compute_width) {
- this.$el.add(this.$records).toggleClass('oe_kanban_group_folded');
- this.state.folded = this.$el.is('.oe_kanban_group_folded');
- this.$("ul.oe_kanban_group_dropdown li a[data-action=toggle_fold]").text((this.state.folded) ? _t("Unfold") : _t("Fold"));
- },
- do_action_toggle_fold: function() {
- this.do_toggle_fold();
- },
- do_action_edit: function() {
- var self = this;
- self.do_action({
- res_id: this.value,
- name: _t("Edit column"),
- res_model: self.view.group_by_field.relation,
- views: [[false, 'form']],
- type: 'ir.actions.act_window',
- target: "new",
- flags: {
- action_buttons: true,
- headless: true,
- }
- });
- // to do : remove this horrible hack
- var am = web_client.action_manager;
- var form = am.dialog_widget.views.form.controller;
- form.on("on_button_cancel", am.dialog, function() { return am.dialog.$dialog_box.modal('hide'); });
- form.on('record_saved', self, function() {
- am.dialog.$dialog_box.modal('hide');
- self.view.do_reload();
- });
- },
- do_action_delete: function() {
- var self = this;
- if (confirm(_t("Are you sure to remove this column ?"))) {
- (new data.DataSet(self, self.view.group_by_field.relation)).unlink([self.value]).done(function(r) {
- self.view.do_reload();
- });
- }
- },
- do_save_sequences: function() {
- var self = this;
- if (_.indexOf(this.view.fields_keys, 'sequence') > -1) {
- var new_sequence = _.pluck(this.records, 'id');
- self.view.dataset.resequence(new_sequence);
- }
- },
- /**
- * Handles a newly created record
- *
- * @param {id} id of the newly created record
- */
- quick_created: function (record) {
- var id = record, self = this;
- self.view.remove_no_result();
- self.trigger("add_record");
- this.dataset.read_ids([id], this.view.fields_keys)
- .done(function (records) {
- self.view.dataset.ids.push(id);
- self.do_add_records(records, true);
- });
- },
- highlight: function(show){
- if(show){
- this.$el.addClass('oe_kanban_column_higlight');
- this.$records.addClass('oe_kanban_column_higlight');
- }else{
- this.$el.removeClass('oe_kanban_column_higlight');
- this.$records.removeClass('oe_kanban_column_higlight');
- }
- }
-});
-
-
-/**
- * Kanban widgets: ProgressBar
- * options
- * - editable: boolean if current_value is editable
- * - current_value: get the current_value from the field that must be present in the view
- * - max_value: get the max_value from the field that must be present in the view
- * - title: title of the gauge, displayed on top of the gauge
- * - on_change: action to call when cliking and setting a value
- */
-var KanbanProgressBar = AbstractField.extend({
- events: {
- 'click': function() {
- if(!this.readonly && this.progressbar.readonly) {
- this.toggle_progressbar();
- }
- }
- },
-
- init: function (parent, field, node) {
- this._super(parent, field, node);
-
- var record = this.getParent().record;
- this.progressbar = new ProgressBar(this, {
- readonly: true,
- value: record[this.options.current_value].raw_value,
- max_value: record[this.options.max_value].raw_value,
- title: this.options.title,
- edit_max_value: this.options.edit_max_value,
- });
-
- this.readonly = !this.options.editable;
- this.on_change = this.options.on_change;
- },
-
- start: function () {
- var self = this;
-
- var def = this.progressbar.appendTo('<div>').done(function() {
- self.progressbar.$el.addClass(self.$el.attr('class'));
- self.replaceElement(self.progressbar.$el);
- });
-
- return $.when(this._super(), def).then(function() {
- if(!self.readonly) {
- var parent = self.getParent();
- self.progressbar.on('change:value change:max_value', self, function(e) {
- var value = this.progressbar.get(this.progressbar.edit_max_value ? 'max_value' : 'value') || 0;
- if(!isNaN(value)) {
- parent.view.dataset.call(this.on_change, [parent.id, value]).then(function() {
- self.toggle_progressbar();
- });
- }
- });
- }
- });
- },
-
- toggle_progressbar: function() {
- this.progressbar.readonly = !this.progressbar.readonly;
- var $div = $('<div/>').insertAfter(this.$el);
- this.progressbar.replace($div);
- this.setElement(this.progressbar.$el);
- },
-});
-
-var fields_registry = new Registry();
-
-fields_registry
- .add('priority', Priority)
- .add('kanban_state_selection', KanbanSelection)
- .add("progress", KanbanProgressBar);
-
-
-return {
- AbstractField: AbstractField,
- registry: fields_registry,
- QuickCreate: QuickCreate,
- KanbanRecord: KanbanRecord,
- KanbanGroup: KanbanGroup,
-};
-
-});
diff --git a/addons/web_kanban/static/src/js/kanban_quick_create.js b/addons/web_kanban/static/src/js/kanban_quick_create.js
new file mode 100644
index 00000000000..3268a2b1acd
--- /dev/null
+++ b/addons/web_kanban/static/src/js/kanban_quick_create.js
@@ -0,0 +1,127 @@
+odoo.define('web_kanban.quick_create', function (require) {
+"use strict";
+
+var Widget = require('web.Widget');
+
+var RecordQuickCreate = Widget.extend({
+ template: "KanbanView.QuickCreate",
+
+ events: {
+ 'click .o_kanban_cancel': 'cancel',
+ 'click .o_kanban_add': 'add_record',
+ 'keypress input': function (event) {
+ if (event.keyCode === 13) {
+ this.add_record();
+ }
+ },
+ 'keydown': function (event) {
+ if (event.keyCode === 27) {
+ this.trigger_up('cancel_quick_create');
+ }
+ },
+ },
+
+ init: function (parent, width) {
+ this._super(parent);
+ this.width = width;
+ },
+
+ start: function () {
+ this.$el.css({width: this.width});
+ this.$input = this.$('input');
+ this.$input.focus();
+ },
+
+ cancel: function () {
+ this.trigger_up('cancel_quick_create');
+ },
+
+ add_record: function () {
+ var value = this.$input.val();
+ this.$input.val('');
+ if (/^\s*$/.test(value)) { return; }
+ this.trigger_up('quick_create_add_record', {value: value});
+ this.$input.focus();
+ },
+});
+
+var ColumnQuickCreate = Widget.extend({
+ template: 'KanbanView.ColumnQuickCreate',
+
+ events: {
+ 'click .o_kanban_add': function (event) {
+ console.log('click okanbanadd');
+ event.stopPropagation();
+ this.add_column();
+ },
+ 'click .o_kanban_quick_create': function (event) {
+ console.log('click quickcreate');
+ event.stopPropagation();
+ },
+ 'keypress input': function (event) {
+ if (event.keyCode === 13) {
+ this.add_column();
+ }
+ },
+ 'click .o_kanban_cancel': function (event) {
+ this.folded = true;
+ this.update();
+ },
+ 'keydown': function (event) {
+ if (event.keyCode === 27) {
+ this.folded = true;
+ this.update();
+ }
+ },
+ },
+
+ init: function (parent) {
+ this._super(parent);
+ this.folded = true;
+ },
+
+ start: function () {
+ this.$header = this.$('.o_column_header');
+ this.$quick_create = this.$('.o_kanban_quick_create');
+ this.$input = this.$('input');
+ this.$el.click(this.proxy('toggle'));
+ var self = this;
+ this.$el.focusout(function () {
+ setTimeout(function() {
+ var hasFocus = !! (self.$(':focus').length > 0);
+ if (! hasFocus) {
+ self.folded = true;
+ self.update();
+ }
+ }, 10);
+ });
+ },
+
+ toggle: function () {
+ this.folded = !this.folded;
+ this.update();
+ if (!this.folded) {
+ this.$input.focus();
+ }
+ },
+
+ update: function () {
+ this.$header.toggle(this.folded);
+ this.$quick_create.toggle(!this.folded);
+ },
+
+ add_column: function () {
+ var name = this.$input.val();
+ this.$input.val('');
+ if (/^\s*$/.test(name)) { return; }
+ this.trigger_up('quick_create_add_column', {value: name});
+ this.$input.focus();
+ }
+});
+
+return {
+ RecordQuickCreate: RecordQuickCreate,
+ ColumnQuickCreate: ColumnQuickCreate,
+};
+
+});
diff --git a/addons/web_kanban/static/src/js/kanban_record.js b/addons/web_kanban/static/src/js/kanban_record.js
new file mode 100644
index 00000000000..9357978d20c
--- /dev/null
+++ b/addons/web_kanban/static/src/js/kanban_record.js
@@ -0,0 +1,275 @@
+odoo.define('web_kanban.Record', function (require) {
+"use strict";
+
+var core = require('web.core');
+var data = require('web.data');
+var formats = require('web.formats');
+var framework = require('web.framework');
+var session = require('web.session');
+var time = require('web.time');
+var utils = require('web.utils');
+var Widget = require('web.Widget');
+var kanban_widgets = require('web_kanban.widgets');
+
+var QWeb = core.qweb;
+var fields_registry = kanban_widgets.registry;
+
+var KanbanRecord = Widget.extend({
+ template: 'KanbanView.record',
+
+ events: {
+ 'click .oe_kanban_action': 'on_kanban_action_clicked',
+ 'click .o_kanban_manage_toggle_button': 'toggle_manage_pane',
+ },
+
+ custom_events: {
+ 'kanban_update_record': 'update_record',
+ },
+
+ init: function (parent, record, options) {
+ this._super(parent);
+
+ this.fields = options.fields;
+ this.editable = options.editable;
+ this.deletable = options.deletable;
+ this.draggable = options.draggable;
+ this.read_only_mode = options.read_only_mode;
+ this.model = options.model;
+ this.group_info = options.group_info;
+ this.qweb = options.qweb;
+ this.sub_widgets = [];
+
+ this.init_content(record);
+ },
+
+ init_content: function (record) {
+ var self = this;
+ this.id = record.id;
+ this.values = {};
+ _.each(record, function(v, k) {
+ self.values[k] = {
+ value: v
+ };
+ });
+ this.record = this.transform_record(record);
+ var qweb_context = {
+ record: this.record,
+ widget: this,
+ read_only_mode: this.read_only_mode,
+ };
+ for (var p in this) {
+ if (_.str.startsWith(p, 'kanban_')) {
+ qweb_context[p] = _.bind(this[p], this);
+ }
+ }
+ this.content = this.qweb.render('kanban-box', qweb_context);
+ },
+
+ add_widgets: function () {
+ var self = this;
+ this.$("field").each(function() {
+ var $field = $(this);
+ var field = self.record[$field.attr("name")];
+ var type = $field.attr("widget") || field.type;
+ var Widget = fields_registry.get(type);
+ var widget = new Widget(self, field, $field);
+ widget.replace($field);
+ self.sub_widgets.push(widget);
+ });
+ },
+
+ start: function() {
+ this.add_widgets();
+ },
+
+ renderElement: function () {
+ this._super();
+ this.setup_color_picker();
+ this.$el.addClass('o_kanban_record');
+ this.$el.data('record', this);
+ if (this.$el.hasClass('oe_kanban_global_click') || this.$el.hasClass('oe_kanban_global_click_edit')) {
+ this.$el.on('click', this.proxy('on_global_click'));
+ }
+ },
+ transform_record: function(record) {
+ var self = this;
+ var new_record = {};
+ _.each(record, function(value, name) {
+ var r = _.clone(self.fields[name] || {});
+ if ((r.type === 'date' || r.type === 'datetime') && value) {
+ r.raw_value = time.auto_str_to_date(value);
+ } else {
+ r.raw_value = value;
+ }
+ r.value = formats.format_value(value, r);
+ new_record[name] = r;
+ });
+ return new_record;
+ },
+
+ update: function (record) {
+ _.invoke(this.sub_widgets, 'destroy');
+ this.sub_widgets = [];
+ this.init_content(record);
+ this.renderElement();
+ this.add_widgets();
+ },
+
+ kanban_image: function(model, field, id, cache, options) {
+ options = options || {};
+ var url;
+ if (this.record[field] && this.record[field].value && !utils.is_bin_size(this.record[field].value)) {
+ url = 'data:image/png;base64,' + this.record[field].value;
+ } else if (this.record[field] && ! this.record[field].value) {
+ url = "/web/static/src/img/placeholder.png";
+ } else {
+ id = JSON.stringify(id);
+ if (options.preview_image)
+ field = options.preview_image;
+ url = session.url('/web/binary/image', {model: model, field: field, id: id});
+ if (cache !== undefined) {
+ // Set the cache duration in seconds.
+ url += '&cache=' + parseInt(cache, 10);
+ }
+ }
+ return url;
+ },
+
+ kanban_getcolor: function(variable) {
+ if (typeof(variable) === 'number') {
+ return Math.round(variable) % 10;
+ }
+ if (typeof(variable) === 'string') {
+ var index = 0;
+ for (var i=0; i<variable.length; i++) {
+ index += variable.charCodeAt(i);
+ }
+ return index % 10;
+ }
+ return 0;
+ },
+
+ kanban_color: function(variable) {
+ var color = this.kanban_getcolor(variable);
+ return 'oe_kanban_color_' + color;
+ },
+
+ on_global_click: function (ev) {
+ if ($(ev.target).parents('.o_dropdown_kanban').length) {
+ return;
+ }
+ if (!ev.isTrigger) {
+ var trigger = true;
+ var elem = ev.target;
+ var ischild = true;
+ var children = [];
+ while (elem) {
+ var events = $._data(elem, 'events');
+ if (elem == ev.currentTarget) {
+ ischild = false;
+ }
+ if (ischild) {
+ children.push(elem);
+ if (events && events.click) {
+ // do not trigger global click if one child has a click event registered
+ trigger = false;
+ }
+ }
+ if (trigger && events && events.click) {
+ _.each(events.click, function(click_event) {
+ if (click_event.selector) {
+ // For each parent of original target, check if a
+ // delegated click is bound to any previously found children
+ _.each(children, function(child) {
+ if ($(child).is(click_event.selector)) {
+ trigger = false;
+ }
+ });
+ }
+ });
+ }
+ elem = elem.parentElement;
+ }
+ if (trigger) {
+ this.on_card_clicked(ev);
+ }
+ }
+ },
+
+ /* actions when user click on the block with a specific class
+ * open on normal view : oe_kanban_global_click
+ * open on form/edit view : oe_kanban_global_click_edit
+ */
+ on_card_clicked: function() {
+ if (this.$el.hasClass('oe_kanban_global_click_edit') && this.$el.data('routing')) {
+ framework.redirect(this.$el.data('routing') + "/" + this.id);
+ } else if (this.$el.hasClass('oe_kanban_global_click_edit')) {
+ this.trigger_up('kanban_record_edit', {id: this.id});
+ } else {
+ this.trigger_up('kanban_record_open', {id: this.id});
+ }
+ },
+
+ toggle_manage_pane: function(event){
+ event.preventDefault();
+ this.$('.o_kanban_card_content').toggleClass('o_visible o_invisible');
+ this.$('.o_kanban_card_manage_pane').toggleClass('o_visible o_invisible');
+ this.$('.o_kanban_manage_button_section').toggleClass(this.kanban_color((this.values['color'] && this.values['color'].value) || 0));
+ },
+
+ on_kanban_action_clicked: function (ev) {
+ ev.preventDefault();
+
+ var $action = $(ev.currentTarget);
+ var type = $action.data('type') || 'button';
+
+ switch (type) {
+ case 'edit':
+ this.trigger_up('kanban_record_edit', {id: this.id});
+ break;
+ case 'open':
+ this.trigger_up('kanban_record_open', {id: this.id});
+ break;
+ case 'delete':
+ this.trigger_up('kanban_record_delete', {record: this});
+ break;
+ case 'action':
+ case 'object':
+ this.trigger_up('kanban_do_action', $action.data());
+ break;
+ default:
+ this.do_warn("Kanban: no action for type : " + type);
+ }
+ },
+
+ kanban_compute_domain: function(domain) {
+ return data.compute_domain(domain, this.values);
+ },
+
+ update_record: function (event) {
+ this.trigger_up('kanban_record_update', event.data);
+ },
+
+ setup_color_picker: function() {
+ var self = this;
+ var $colorpicker = this.$('ul.oe_kanban_colorpicker');
+ if (!$colorpicker.length) {
+ return;
+ }
+ $colorpicker.html(QWeb.render('KanbanColorPicker', {
+ widget: this
+ }));
+ $colorpicker.on('click', 'a', function(ev) {
+ ev.preventDefault();
+ var color_field = $colorpicker.data('field') || 'color';
+ var data = {};
+ data[color_field] = $(this).data('color');
+ self.trigger_up('kanban_record_update', data);
+ });
+ },
+
+});
+
+return KanbanRecord;
+
+});
diff --git a/addons/web_kanban/static/src/js/kanban_view.js b/addons/web_kanban/static/src/js/kanban_view.js
index a488267752a..5d60fc1aeb8 100644
--- a/addons/web_kanban/static/src/js/kanban_view.js
+++ b/addons/web_kanban/static/src/js/kanban_view.js
@@ -4,24 +4,49 @@ odoo.define('web_kanban.KanbanView', function (require) {
var core = require('web.core');
var data = require('web.data');
var Model = require('web.Model');
+var Dialog = require('web.Dialog');
+var form_common = require('web.form_common');
+var Pager = require('web.Pager');
var pyeval = require('web.pyeval');
var session = require('web.session');
var utils = require('web.utils');
var View = require('web.View');
-var kanban_common = require('web_kanban.common');
+
+var KanbanColumn = require('web_kanban.Column');
+var quick_create = require('web_kanban.quick_create');
+var KanbanRecord = require('web_kanban.Record');
+var kanban_widgets = require('web_kanban.widgets');
var QWeb = core.qweb;
-var _t = core._t;
var _lt = core._lt;
-var fields_registry = kanban_common.registry;
-var KanbanGroup = kanban_common.KanbanGroup;
+var _t = core._t;
+var ColumnQuickCreate = quick_create.ColumnQuickCreate;
+var fields_registry = kanban_widgets.registry;
var KanbanView = View.extend({
- template: "KanbanView",
- display_name: _lt('Kanban'),
- default_nr_columns: 1,
+ display_name: _lt("Kanban"),
view_type: "kanban",
- number_of_color_schemes: 10,
+ className: "o_kanban_view",
+ mobile_friendly: true,
+
+ custom_events: {
+ 'kanban_record_open': 'open_record',
+ 'kanban_record_edit': 'edit_record',
+ 'kanban_record_delete': 'delete_record',
+ 'kanban_do_action': 'open_action',
+ 'kanban_reload': 'do_reload',
+ 'kanban_column_resequence': function (event) {
+ this.resequence_column(event.target);
+ },
+ 'kanban_record_update': 'update_record',
+ 'kanban_column_add_record': 'add_record_to_column',
+ 'kanban_column_delete': 'delete_column',
+ 'column_add_record': 'column_add_record',
+ 'quick_create_add_column': 'add_new_column',
+ 'kanban_load_more': 'load_more',
+ 'kanban_call_method': 'call_method',
+ },
+
init: function (parent, dataset, view_id, options) {
this._super(parent, dataset, view_id, options);
_.defaults(this.options, {
@@ -31,111 +56,42 @@ var KanbanView = View.extend({
"read_only_mode": false,
"confirm_on_delete": true,
});
- this.fields_view = {};
- this.fields_keys = [];
- this.group_by = null;
- this.group_by_field = {};
- this.grouped_by_m2o = false;
- this.many2manys = [];
- this.m2m_context = {};
- this.state = {
- groups : {},
- records : {}
- };
- this.groups = [];
+
+ // qweb setup
this.qweb = new QWeb2.Engine();
this.qweb.debug = session.debug;
this.qweb.default_dict = _.clone(QWeb.default_dict);
- this.has_been_loaded = $.Deferred();
- this.search_domain = this.search_context = this.search_group_by = null;
- this.currently_dragging = {};
+
+ this.model = this.dataset.model;
this.limit = options.limit || 40;
- this.add_group_mutex = new utils.Mutex();
- },
- view_loading: function(r) {
- return this.load_kanban(r);
- },
- start: function() {
- var self = this;
- this._super.apply(this, arguments);
- this.$el.on('click', '.oe_kanban_dummy_cell', function() {
- if (self.$buttons) {
- self.$buttons.find('.oe_kanban_add_column').openerpBounce();
- }
- });
- },
- destroy: function() {
- this._super.apply(this, arguments);
- $('html').off('click.kanban');
- },
- get_quick_create_class: function () {
- return kanban_common.QuickCreate;
+ this.grouped = undefined;
+ this.group_by_field = undefined;
+ this.default_group_by = undefined;
+ this.grouped_by_m2o = undefined;
+ this.relation = undefined;
+ this.is_empty = undefined;
+ this.many2manys = [];
+ this.m2m_context = {};
+ this.widgets = [];
+ this.data = undefined;
+ this.model = dataset.model;
+ this.quick_creatable = options.quick_creatable;
+ this.no_content_msg = options.action && (options.action.get_empty_list_help || options.action.help);
+
},
- load_kanban: function(data) {
- this.fields_view = data;
- // use default order if defined in xml description
- var default_order = this.fields_view.arch.attrs.default_order,
- unsorted = !this.dataset._sort.length;
- if (unsorted && default_order) {
- this.dataset.set_sort(default_order.split(','));
- }
- this.$el.addClass(this.fields_view.arch.attrs['class']);
- this.$groups = this.$el.find('.oe_kanban_groups tr');
+ view_loading: function(fvg) {
+ this.$el.addClass(fvg.arch.attrs.class);
+ this.fields_view = fvg;
+ this.default_group_by = fvg.arch.attrs.default_group_by;
+
this.fields_keys = _.keys(this.fields_view.fields);
- this.add_qweb_template();
- this.has_been_loaded.resolve();
- this.trigger('kanban_view_loaded', data);
- return $.when();
- },
- /**
- * Render the buttons according to the KanbanView.buttons template and
- * add listeners on it.
- * Set this.$buttons with the produced jQuery element
- * @param {jQuery} [$node] a jQuery node where the rendered buttons should be inserted
- * $node may be undefined, in which case the ListView inserts them into this.options.$buttons
- * or into a div of its template
- */
- render_buttons: function($node) {
- var display = false;
- if (this.options.action_buttons !== false) {
- display = this.is_action_enabled('create');
- } else if (!this.view_id && !this.options.read_only_mode) {
- display = this.is_action_enabled('write') || this.is_action_enabled('create');
- }
- this.$buttons = $(QWeb.render("KanbanView.buttons", {'widget': this, display: display}));
- this.$buttons
- .on('click', 'button.oe_kanban_button_new', this.do_add_record)
- .on('click', '.oe_kanban_add_column', this.do_add_group);
- // Important: This should be done after do_search is finished so that
- // this.grouped_by_m2o is set
- this.$buttons.find('.oe_alternative').toggle(this.grouped_by_m2o);
- $node = $node || this.options.$buttons;
- if ($node) {
- this.$buttons.appendTo($node);
- } else {
- this.$('.oe_kanban_buttons').replaceWith(this.$buttons);
- }
- },
- _is_quick_create_enabled: function() {
- if (!this.options.quick_creatable || !this.is_action_enabled('create'))
- return false;
- if (this.fields_view.arch.attrs.quick_create !== undefined)
- return JSON.parse(this.fields_view.arch.attrs.quick_create);
- return !! this.group_by;
- },
- is_action_enabled: function(action) {
- if (action === 'create' && !this.options.creatable)
- return false;
- return this._super(action);
- },
- /* add_qweb_template */
- add_qweb_template: function() {
+ // add qweb templates
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);
+ transform_qweb_template(child, fvg, this.many2manys);
this.qweb.add_template(utils.json_node_to_xml(child));
break;
} else if (child.tag === 'field') {
@@ -146,164 +102,130 @@ var KanbanView = View.extend({
}
}
},
- transform_qweb_template: function(node) {
- var qweb_add_if = function(node, condition) {
- if (node.attrs[QWeb.prefix + '-if']) {
- condition = _.str.sprintf("(%s) and (%s)", node.attrs[QWeb.prefix + '-if'], condition);
- }
- node.attrs[QWeb.prefix + '-if'] = condition;
- };
- // Process modifiers
- if (node.tag && node.attrs.modifiers) {
- var modifiers = JSON.parse(node.attrs.modifiers || '{}');
- if (modifiers.invisible) {
- qweb_add_if(node, _.str.sprintf("!kanban_compute_domain(%s)", JSON.stringify(modifiers.invisible)));
- }
- }
- switch (node.tag) {
- case 'field':
- var ftype = this.fields_view.fields[node.attrs.name].type;
- ftype = node.attrs.widget ? node.attrs.widget : ftype;
- if (ftype === 'many2many') {
- if (_.indexOf(this.many2manys, node.attrs.name) < 0) {
- this.many2manys.push(node.attrs.name);
- }
- node.tag = 'div';
- node.attrs['class'] = (node.attrs['class'] || '') + ' oe_form_field oe_tags';
- } else if (fields_registry.contains(ftype)) {
- // do nothing, the kanban record will handle it
- } else {
- node.tag = QWeb.prefix;
- node.attrs[QWeb.prefix + '-esc'] = 'record.' + node.attrs['name'] + '.value';
- }
- break;
- case 'button':
- case 'a':
- var type = node.attrs.type || '';
- if (_.indexOf('action,object,edit,open,delete,url'.split(','), type) !== -1) {
- _.each(node.attrs, function(v, k) {
- if (_.indexOf('icon,type,name,args,string,context,states,kanban_states'.split(','), k) != -1) {
- node.attrs['data-' + k] = v;
- delete(node.attrs[k]);
- }
- });
- if (node.attrs['data-string']) {
- node.attrs.title = node.attrs['data-string'];
- }
- if (node.attrs['data-icon']) {
- node.children = [{
- tag: 'img',
- attrs: {
- src: session.prefix + '/web/static/src/img/icons/' + node.attrs['data-icon'] + '.png',
- width: '16',
- height: '16'
- }
- }];
- }
- if (node.tag == 'a' && node.attrs['data-type'] != "url") {
- 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]);
- }
- }
+
+ do_search: function(domain, context, group_by) {
+ this.search_domain = domain;
+ this.search_context = context;
+ this.group_by_field = group_by[0] || this.default_group_by;
+ this.grouped = group_by.length || this.default_group_by;
+
+ var field = this.fields_view.fields[this.group_by_field];
+ this.grouped_by_m2o = field && (field.type === 'many2one');
+ this.relation = this.grouped_by_m2o ? field.relation : undefined;
+
+ return this.load_data()
+ .then(this.proxy('render'))
+ .then(this.proxy('update_pager'));
},
- do_add_record: function() {
- this.dataset.index = null;
- this.do_switch_view('form');
+
+ do_show: function() {
+ this.do_push_state({});
+ return this._super();
},
- do_add_group: function() {
+
+ do_reload: function() {
+ this.do_search(this.search_domain, this.search_context, [this.group_by_field]);
},
- do_search: function(domain, context, group_by) {
+
+ load_data: function () {
var self = this;
- this.search_domain = domain;
- this.search_context = context;
- this.search_group_by = group_by;
- return $.when(this.has_been_loaded).then(function() {
- self.group_by = group_by.length ? group_by[0] : self.fields_view.arch.attrs.default_group_by;
- self.group_by_field = self.fields_view.fields[self.group_by] || {};
- self.grouped_by_m2o = (self.group_by_field.type === 'many2one');
- self.$el.toggleClass('oe_kanban_grouped_by_m2o', self.grouped_by_m2o);
- var grouping_fields = self.group_by ? [self.group_by] : undefined;
- if (!_.isEmpty(grouping_fields)) {
- // ensure group_by fields are read.
- self.fields_keys = _.unique(self.fields_keys.concat(grouping_fields));
- }
- var grouping = new Model(self.dataset.model, context, domain).query(self.fields_keys).group_by(grouping_fields);
- return self.alive($.when(grouping)).then(function(groups) {
- self.remove_no_result();
- if (groups) {
- return self.do_process_groups(groups);
- } else {
- return self.do_process_dataset();
- }
- });
+ var deferred = this.grouped ? this.load_groups() : this.load_records();
+ return deferred.then(function (data) {
+ self.data = data;
});
},
- do_process_groups: function(groups) {
- var self = this;
- // Check in the arch the fields to fetch on the stage to get tooltips data.
- // Fetching data is done in batch for all stages, to avoid doing multiple
- // calls. The first naive implementation of group_by_tooltip made a call
- // for each displayed stage and was quite limited.
- // Data for the group tooltip (group_by_tooltip) and to display stage-related
- // legends for kanban state management (states_legend) are fetched in
- // one call.
- var group_by_fields_to_read = [];
- var recurse = function(node) {
- if (node.tag === "field" && node.attrs && node.attrs.options) {
- var options = pyeval.py_eval(node.attrs.options);
- var states_fields_to_read = _.map(
- options && options.states_legend || {},
- function (value, key, list) { return value; });
- var tooltip_fields_to_read = _.map(
- options && options.group_by_tooltip || {},
- function (value, key, list) { return key; });
- group_by_fields_to_read = _.union(
- group_by_fields_to_read,
- states_fields_to_read,
- tooltip_fields_to_read);
- }
- _.each(node.children, function(child) {
- recurse(child);
- });
+ load_records: function (offset, dataset) {
+ var options = {
+ 'limit': this.limit,
+ 'offset': offset,
};
- recurse(this.fields_view.arch);
- var group_ids = _.without(_.map(groups, function (elem) { return elem.attributes.value[0];}), undefined);
- if (this.grouped_by_m2o && group_ids.length && group_by_fields_to_read.length) {
- var group_data = new data.DataSet(
- this,
- this.group_by_field.relation).read_ids(group_ids, _.union(['display_name'], group_by_fields_to_read));
- }
- else { var group_data = $.Deferred().resolve({}); }
-
- this.$el.find('table:first').show();
- this.$el.removeClass('oe_kanban_ungrouped').addClass('oe_kanban_grouped');
- return $.when(group_data).then(function (results) {
- _.each(results, function (group_by_data) {
- var group = _.find(groups, function (elem) {return elem.attributes.value[0] == group_by_data.id;});
- if (group) {
- group.values = group_by_data;
- }
+ dataset = dataset || this.dataset;
+ return dataset
+ .read_slice(this.fields_keys.concat(['__last_update']), options)
+ .then(function(records) {
+ return {
+ records: records,
+ is_empty: !records.length,
+ grouped: false,
+ };
});
- }).done( function () {return self.add_group_mutex.exec(function() {
- self.do_clear_groups();
- self.dataset.ids = [];
- if (!groups.length) {
- self.no_result();
- return $.when();
+ },
+
+ load_groups: function () {
+ var self = this;
+ var group_by_field = this.group_by_field || this.default_group_by;
+ this.fields_keys = _.uniq(this.fields_keys.concat(group_by_field));
+
+ return new Model(this.model, this.search_context, this.search_domain)
+ .query(this.fields_keys)
+ .group_by([group_by_field])
+ .then(function (groups) {
+
+ // Check in the arch the fields to fetch on the stage to get tooltips data.
+ // Fetching data is done in batch for all stages, to avoid doing multiple
+ // calls. The first naive implementation of group_by_tooltip made a call
+ // for each displayed stage and was quite limited.
+ // Data for the group tooltip (group_by_tooltip) and to display stage-related
+ // legends for kanban state management (states_legend) are fetched in
+ // one call.
+ var group_by_fields_to_read = [];
+ var recurse = function(node) {
+ if (node.tag === "field" && node.attrs && node.attrs.options) {
+ var options = pyeval.py_eval(node.attrs.options);
+ var states_fields_to_read = _.map(
+ options && options.states_legend || {},
+ function (value, key, list) { return value; });
+ var tooltip_fields_to_read = _.map(
+ options && options.group_by_tooltip || {},
+ function (value, key, list) { return key; });
+ group_by_fields_to_read = _.union(
+ group_by_fields_to_read,
+ states_fields_to_read,
+ tooltip_fields_to_read);
+ }
+ _.each(node.children, function(child) {
+ recurse(child);
+ });
+ };
+ recurse(self.fields_view.arch);
+
+ // fetch group data (display information)
+ var group_ids = _.without(_.map(groups, function (elem) { return elem.attributes.value[0];}), undefined);
+ if (self.grouped_by_m2o && group_ids.length) {
+ return new data.DataSet(self, self.relation)
+ .read_ids(group_ids, _.union(['display_name'], group_by_fields_to_read))
+ .then(function(results) {
+ _.each(groups, function (group) {
+ var group_id = group.attributes.value[0];
+ var result = _.find(results, function (data) {return group_id === data.id;});
+ group.title = result ? result.display_name : _t("Undefined");
+ group.values = result;
+ group.id = group_id;
+ });
+ return groups;
+ });
+ } else {
+ _.each(groups, function (group) {
+ var value = group.attributes.value;
+ group.title = (value instanceof Array ? value[1] : value) || _t("Undefined");
+ });
+ return $.when(groups);
}
- self.nb_records = 0;
- var groups_array = [];
- return $.when.apply(null, _.map(groups, function (group, index) {
+ })
+ .then(function (groups) {
+ var undef_index = _.findIndex(groups, function (g) { return g.title === _t("Undefined");});
+ if (undef_index >= 1) {
+ var undef_group = groups[undef_index];
+ groups.splice(undef_index, 1);
+ groups.unshift(undef_group);
+ }
+ return groups;
+ })
+ .then(function (groups) {
+ // load records for each group
+ var is_empty = true;
+ return $.when.apply(null, _.map(groups, function (group) {
var def = $.when([]);
var dataset = new data.DataSetSearch(self, self.dataset.model,
new data.CompoundContext(self.dataset.get_context(), group.model.context()), group.model.domain());
@@ -313,275 +235,273 @@ var KanbanView = View.extend({
if (group.attributes.length >= 1) {
def = dataset.read_slice(self.fields_keys.concat(['__last_update']), { 'limit': self.limit });
}
- return def.then(function(records) {
- self.nb_records += records.length;
- self.dataset.ids.push.apply(self.dataset.ids, dataset.ids);
- groups_array[index] = new KanbanGroup(self, records, group, dataset);
+ return def.then(function (records) {
+ self.dataset.ids.push.apply(self.dataset.ids, dataset.ids);
+ group.records = records;
+ group.dataset = dataset;
+ is_empty = is_empty && !records.length;
+ return group;
});
})).then(function () {
- if(!self.nb_records) {
- self.no_result();
- }
- if (self.dataset.index >= self.nb_records){
- self.dataset.index = self.dataset.size() ? 0 : null;
- }
- return self.do_add_groups(groups_array).done(function() {
- self.trigger('kanban_groups_processed');
- });
- });
- });});
- },
- do_process_dataset: function() {
- var self = this;
- this.$el.find('table:first').show();
- this.$el.removeClass('oe_kanban_grouped').addClass('oe_kanban_ungrouped');
- var def = $.Deferred();
- this.add_group_mutex.exec(function() {
- self.do_clear_groups();
- self.dataset.read_slice(self.fields_keys.concat(['__last_update']), { 'limit': self.limit }).done(function(records) {
- var kgroup = new KanbanGroup(self, records, null, self.dataset);
- if (!_.isEmpty(self.dataset.ids) && (self.dataset.index === null || self.dataset.index >= self.dataset.ids.length)) {
- self.dataset.index = 0;
- } else if (_.isEmpty(self.dataset.ids)){
- self.dataset.index = null;
- }
- self.do_add_groups([kgroup]).done(function() {
- if (_.isEmpty(records)) {
- self.no_result();
- }
- self.trigger('kanban_dataset_processed');
- def.resolve();
- });
- }).done(null, function() {
- def.reject();
+ return {
+ groups: Array.prototype.slice.call(arguments, 0),
+ is_empty: is_empty,
+ grouped: true,
+ };
});
return def;
});
- return def;
},
- do_reload: function() {
- this.do_search(this.search_domain, this.search_context, this.search_group_by);
+
+ is_action_enabled: function(action) {
+ if (action === 'create' && !this.options.creatable) {
+ return false;
+ }
+ return this._super(action);
},
- do_clear_groups: function() {
- var groups = this.groups.slice(0);
- this.groups = [];
- _.each(groups, function(group) {
- group.destroy();
- });
+ _is_quick_create_enabled: function() {
+ if (!this.quick_creatable || !this.is_action_enabled('create'))
+ return false;
+ if (this.fields_view.arch.attrs.quick_create !== undefined)
+ return JSON.parse(this.fields_view.arch.attrs.quick_create);
+ return !!this.grouped;
},
- do_add_groups: function(groups) {
+ /**
+ * Render the buttons according to the KanbanView.buttons template and
+ * add listeners on it.
+ * Set this.$buttons with the produced jQuery element
+ * @param {jQuery} [$node] a jQuery node where the rendered buttons should be inserted
+ * $node may be undefined, in which case the ListView inserts them into this.options.$buttons
+ */
+ render_buttons: function($node) {
+ var display = false;
+ if (this.options.action_buttons !== false) {
+ display = this.is_action_enabled('create');
+ } else if (!this.view_id && !this.options.read_only_mode) {
+ display = this.is_action_enabled('write') || this.is_action_enabled('create');
+ }
+ this.$buttons = $(QWeb.render("KanbanView.buttons", {'widget': this, display: display}));
+ this.$buttons.on('click', 'button.o-kanban-button-new', this.add_record.bind(this));
+
+ $node = $node || this.options.$buttons;
+ this.$buttons.appendTo($node);
+ },
+
+ render_pager: function($node, options) {
var self = this;
- var $parent = this.$el.parent();
- this.$el.detach();
- _.each(groups, function(group) {
- self.groups[group.undefined_title ? 'unshift' : 'push'](group);
- });
- var $last_td = self.$el.find('.oe_kanban_groups_headers td:last');
- var groups_started = _.map(this.groups, function(group) {
- if (!group.is_started) {
- group.on("add_record", self, function () {
- self.remove_no_result();
- });
- return group.insertBefore($last_td);
- }
- });
- return $.when.apply(null, groups_started).done(function () {
- self.on_groups_started();
- self.$el.appendTo($parent);
- _.each(self.groups, function(group) {
- group.compute_cards_auto_height();
- });
+ this.pager = new Pager(this, this.dataset.size(), 1, this.limit, options);
+ this.pager.appendTo($node);
+ this.pager.on('pager_changed', this, function (state) {
+ self.load_records(state.current_min - 1)
+ .then(function (data) {
+ self.data = data;
+ })
+ .done(this.proxy('render'));
});
+ this.update_pager();
},
- on_groups_started: function() {
- var self = this;
- if (this.group_by || this.fields_keys.indexOf("sequence") !== -1) {
- // Kanban cards drag'n'drop
- var prev_widget, is_folded, record, $columns;
- if (this.group_by) {
- $columns = this.$el.find('.oe_kanban_column .oe_kanban_column_cards, .oe_kanban_column .oe_kanban_folded_column_cards');
+
+ update_pager: function() {
+ if (this.pager) {
+ if (this.grouped) {
+ this.pager.do_hide();
} else {
- $columns = this.$el.find('.oe_kanban_column_cards');
- }
- $columns.sortable({
- handle : '.oe_kanban_draghandle',
- start: function(event, ui) {
- self.currently_dragging.index = ui.item.parent().children('.oe_kanban_record').index(ui.item);
- self.currently_dragging.group = prev_widget = ui.item.parents('.oe_kanban_column:first').data('widget');
- ui.item.find('*').on('click.prevent', function(ev) {
- return false;
- });
- record = ui.item.data('widget');
- record.$el.bind('mouseup',function(ev,ui){
- if (is_folded) {
- record.$el.hide();
- }
- record.$el.unbind('mouseup');
- });
- ui.placeholder.height(ui.item.height());
- },
- over: function(event, ui) {
- var parent = $(event.target).parent();
- prev_widget.highlight(false);
- is_folded = parent.hasClass('oe_kanban_group_folded');
- if (is_folded) {
- var widget = parent.data('widget');
- widget.highlight(true);
- prev_widget = widget;
- }
- },
- revert: 150,
- stop: function(event, ui) {
- prev_widget.highlight(false);
- var old_index = self.currently_dragging.index;
- var new_index = ui.item.parent().children('.oe_kanban_record').index(ui.item);
- var old_group = self.currently_dragging.group;
- var new_group = ui.item.parents('.oe_kanban_column:first').data('widget');
- if (!(old_group.title === new_group.title && old_group.value === new_group.value && old_index == new_index)) {
- self.on_record_moved(record, old_group, old_index, new_group, new_index);
- }
- setTimeout(function() {
- // A bit hacky but could not find a better solution for Firefox (problem not present in chrome)
- // http://stackoverflow.com/questions/274843/preventing-javascript-click-event-with-scriptaculous-drag-and-drop
- ui.item.find('*').off('click.prevent');
- }, 0);
- },
- scroll: false
- });
- // Keep connectWith out of the sortable initialization for performance sake:
- // http://www.planbox.com/blog/development/coding/jquery-ui-sortable-slow-to-bind.html
- $columns.sortable({ connectWith: $columns });
-
- // Kanban groups drag'n'drop
- var start_index;
- if (this.grouped_by_m2o) {
- this.$('.oe_kanban_groups_headers').sortable({
- items: '.oe_kanban_group_header',
- helper: 'clone',
- axis: 'x',
- opacity: 0.5,
- scroll: false,
- start: function(event, ui) {
- start_index = ui.item.index();
- self.$('.oe_kanban_record, .oe_kanban_quick_create').css({ visibility: 'hidden' });
- },
- stop: function(event, ui) {
- var stop_index = ui.item.index();
- if (start_index !== stop_index) {
- var $start_column = self.$('.oe_kanban_groups_records .oe_kanban_column').eq(start_index);
- var $stop_column = self.$('.oe_kanban_groups_records .oe_kanban_column').eq(stop_index);
- var method = (start_index > stop_index) ? 'insertBefore' : 'insertAfter';
- $start_column[method]($stop_column);
- var tmp_group = self.groups.splice(start_index, 1)[0];
- self.groups.splice(stop_index, 0, tmp_group);
- var new_sequence = _.pluck(self.groups, 'value');
- (new data.DataSet(self, self.group_by_field.relation)).resequence(new_sequence).done(function(r) {
- if (r === false) {
- console.error("Kanban: could not resequence model '%s'. Probably no 'sequence' field.", self.group_by_field.relation);
- }
- });
- }
- self.$('.oe_kanban_record, .oe_kanban_quick_create').css({ visibility: 'visible' });
- }
- });
+ this.pager.set_state({size: this.dataset.size(), current_min: 1});
}
+ }
+ },
+
+ render: function () {
+ // cleanup
+ this.$el.css({display:'-webkit-flex'});
+ this.$el.css({display:'flex'});
+ this.$el.removeClass('o_kanban_ungrouped o_kanban_grouped');
+ _.invoke(this.widgets, 'destroy');
+ this.$el.empty();
+ this.widgets = [];
+ if (this.column_quick_create) {
+ this.column_quick_create.destroy();
+ this.column_quick_create = undefined;
+ }
+
+ this.record_options = {
+ editable: this.is_action_enabled('edit'),
+ deletable: this.is_action_enabled('delete'),
+ fields: this.fields_view.fields,
+ qweb: this.qweb,
+ model: this.model,
+ read_only_mode: this.options.read_only_mode,
+ };
+
+ // actual rendering
+ var fragment = document.createDocumentFragment();
+ if (this.data.grouped) {
+ this.$el.addClass('o_kanban_grouped');
+ this.render_grouped(fragment);
+ } else if (this.data.is_empty) {
+ this.render_no_content(fragment);
} else {
- this.$el.find('.oe_kanban_draghandle').removeClass('oe_kanban_draghandle');
+ this.$el.addClass('o_kanban_ungrouped');
+ this.render_ungrouped(fragment);
+ }
+ this.$el.append(fragment);
+ },
+
+ render_no_content: function (fragment) {
+ var content = QWeb.render('KanbanView.nocontent', {content: this.no_content_msg});
+ $(content).appendTo(fragment);
+ },
+
+ render_ungrouped: function (fragment) {
+ var self = this;
+ var options = _.clone(this.record_options);
+ _.each(this.data.records, function (record) {
+ var kanban_record = new KanbanRecord(self, record, options);
+ self.widgets.push(kanban_record);
+ kanban_record.appendTo(fragment);
+ });
+
+ // add empty invisible divs to make sure that all kanban records are left aligned
+ for (var i = 0, ghost_div; i < 6; i++) {
+ ghost_div = $("<div>").addClass("o_kanban_record o_kanban_ghost");
+ ghost_div.appendTo(fragment);
}
this.postprocess_m2m_tags();
},
- on_record_moved : function(record, old_group, old_index, new_group, new_index) {
+
+ get_column_options: function () {
+ return {
+ editable: this.is_action_enabled('group_edit'),
+ deletable: this.is_action_enabled('group_delete'),
+ grouped_by_m2o: this.grouped_by_m2o,
+ relation: this.relation,
+ qweb: this.qweb,
+ fields: this.fields_view.fields,
+ quick_create: this._is_quick_create_enabled(),
+ };
+ },
+
+ render_grouped: function (fragment) {
var self = this;
- record.$el.find('[title]').tooltip('destroy');
- $(old_group.$el).add(new_group.$el).find('.oe_kanban_group_length').hide();
- if (old_group === new_group) {
- new_group.records.splice(old_index, 1);
- new_group.records.splice(new_index, 0, record);
- new_group.do_save_sequences();
- } else {
- old_group.records.splice(old_index, 1);
- new_group.records.splice(new_index, 0, record);
- record.group = new_group;
- var data = {};
- data[this.group_by] = new_group.value;
- this.dataset.write(record.id, data, {}).done(function() {
- record.do_reload();
- new_group.do_save_sequences();
- if (new_group.state.folded) {
- new_group.do_action_toggle_fold();
- record.prependTo(new_group.$records.find('.oe_kanban_column_cards'));
- }
- }).fail(function(error, evt) {
- evt.preventDefault();
- alert(_t("An error has occured while moving the record to this group: ") + error.data.message);
- self.do_reload(); // TODO: use draggable + sortable in order to cancel the dragging when the rcp fails
- });
+ var record_options = _.extend(this.record_options, {
+ draggable: true,
+ });
+
+ var column_options = this.get_column_options();
+
+ _.each(this.data.groups, function (group) {
+ var column = new KanbanColumn(self, group, column_options, record_options);
+ column.appendTo(fragment);
+ self.widgets.push(column);
+ });
+ this.$el.sortable({
+ axis: 'x',
+ items: '> .o_kanban_group',
+ cursor: 'move',
+ revert: 150,
+ delay: 100,
+ tolerance: 'pointer',
+ forcePlaceholderSize: true,
+ stop: function () {
+ var ids = [];
+ self.$('.o_kanban_group').each(function (index, u) {
+ ids.push($(u).data('id'));
+ });
+ self.resequence(ids);
+ },
+ });
+ if (this.is_action_enabled('group_create')) {
+ this.column_quick_create = new ColumnQuickCreate(this);
+ this.column_quick_create.appendTo(fragment);
}
+ this.postprocess_m2m_tags();
},
- do_show: function() {
- this.do_push_state({});
- return this._super();
+ add_record: function() {
+ this.dataset.index = null;
+ this.do_switch_view('form');
},
- open_record: function(id, editable) {
- if (this.dataset.select_id(id)) {
- this.do_switch_view('form', null, { mode: editable ? "edit" : undefined });
+
+ open_record: function (event, options) {
+ if (this.dataset.select_id(event.data.id)) {
+ this.do_switch_view('form', null, options); //, null, { mode: "edit" });
} else {
- this.do_warn("Kanban: could not find id#" + id);
+ this.do_warn("Kanban: could not find id#" + event.data.id);
}
},
- no_result: function() {
+
+ edit_record: function (event) {
+ this.open_record(event, {mode: 'edit'});
+ },
+
+ delete_record: function (event) {
var self = this;
- if (this.groups.group_by
- || !this.options.action
- || (!this.options.action.help && !this.options.action.get_empty_list_help)) {
- return;
+ var record = event.data.record;
+ function do_it() {
+ return $.when(self.dataset.unlink([record.id])).done(function() {
+ record.destroy();
+ if (event.data.after) {
+ event.data.after();
+ }
+ });
+ }
+ if (this.options.confirm_on_delete) {
+ Dialog.confirm(this, _t("Are you sure you want to delete this record ?"), do_it);
+ } else {
+ do_it();
}
- this.$el.css("position", "relative");
- $(QWeb.render('KanbanView.nocontent', { content : this.options.action.get_empty_list_help || this.options.action.help})).insertBefore(this.$('table:first'));
- this.$el.find('.oe_view_nocontent').click(function() {
- self.$buttons.openerpBounce();
- });
},
- remove_no_result: function() {
- this.$el.css("position", "");
- this.$el.find('.oe_view_nocontent').remove();
+
+ open_action: function (event) {
+ var self = this;
+ var node_context = event.data.context || {};
+ var context = new data.CompoundContext(node_context);
+ context.set_eval_context({
+ active_id: event.target.id,
+ active_ids: [event.target.id],
+ active_model: this.dataset.model,
+ });
+ this.do_execute_action(event.data, this.dataset, event.target.id).then(function () {
+ self.reload_record(event.target);
+ });
},
/*
* postprocessing of fields type many2many
* make the rpc request for all ids/model and insert value inside .oe_tags fields
*/
- postprocess_m2m_tags: function() {
+ postprocess_m2m_tags: function(records) {
var self = this;
if (!this.many2manys.length) {
return;
}
var relations = {};
- this.groups.forEach(function(group) {
- group.records.forEach(function(record) {
- self.many2manys.forEach(function(name) {
- var field = record.record[name];
- var $el = record.$('.oe_form_field.oe_tags[name=' + name + ']').empty();
- // fields declared in the kanban view may not be used directly
- // in the template declaration, for example fields for which the
- // raw value is used -> $el[0] is undefined, leading to errors
- // in the following process. Preventing to add push the id here
- // prevents to make unnecessary calls to name_get
- if (! $el[0]) {
- return;
- }
- if (!relations[field.relation]) {
- relations[field.relation] = { ids: [], elements: {}, context: self.m2m_context[name]};
+ records = records ? (records instanceof Array ? records : [records]) :
+ this.grouped ? Array.prototype.concat.apply([], _.pluck(this.widgets, 'records')) :
+ this.widgets;
+
+ records.forEach(function(record) {
+ self.many2manys.forEach(function(name) {
+ var field = record.record[name];
+ var $el = record.$('.oe_form_field.oe_tags[name=' + name + ']');
+ // fields declared in the kanban view may not be used directly
+ // in the template declaration, for example fields for which the
+ // raw value is used -> $el[0] is undefined, leading to errors
+ // in the following process. Preventing to add push the id here
+ // prevents to make unnecessary calls to name_get
+ if (! $el[0]) {
+ return;
+ }
+ if (!relations[field.relation]) {
+ relations[field.relation] = { ids: [], elements: {}, context: self.m2m_context[name]};
+ }
+ var rel = relations[field.relation];
+ field.raw_value.forEach(function(id) {
+ rel.ids.push(id);
+ if (!rel.elements[id]) {
+ rel.elements[id] = [];
}
- var rel = relations[field.relation];
- field.raw_value.forEach(function(id) {
- rel.ids.push(id);
- if (!rel.elements[id]) {
- rel.elements[id] = [];
- }
- rel.elements[id].push($el[0]);
- });
+ rel.elements[id].push($el[0]);
});
});
});
@@ -589,68 +509,253 @@ var KanbanView = View.extend({
var dataset = new data.DataSetSearch(self, rel_name, self.dataset.get_context(rel.context));
dataset.name_get(_.uniq(rel.ids)).done(function(result) {
result.forEach(function(nameget) {
- $(rel.elements[nameget[0]]).append('<span class="oe_tag">' + _.str.escapeHTML(nameget[1]) + '</span>');
+ // white color (0) should not be selected, 1 instead
+ var color = KanbanRecord.prototype.kanban_getcolor(nameget[1]) + 1;
+ var $tag = $('<span>')
+ .addClass('o_tag oe_kanban_color_' + color)
+ .attr('title', _.str.escapeHTML(nameget[1]));
+ $(rel.elements[nameget[0]]).append($tag);
});
+ // we use boostrap tooltips for better and faster display
+ self.$('span.o_tag').tooltip();
});
});
- }
-});
+ },
+ resequence: function (ids) {
+ if ((ids.length <= 1) || !this.relation) {
+ return;
+ }
+ new data.DataSet(this, this.relation).resequence(ids).done(function (r) {
+ if (!r) {
+ console.warn('Resequence could not be complete. ' +
+ 'Maybe the model does not have a "sequence" field?');
+ }
+ });
+ },
-core.view_registry.add('kanban', KanbanView);
+ resequence_column: function (col) {
+ if (_.indexOf(this.fields_keys, 'sequence') > -1) {
+ this.dataset.resequence(col.get_ids());
+ }
+ },
-return KanbanView;
+ delete_column: function (event) {
+ var self = this;
+ var column = event.target;
+ (new data.DataSet(this, this.relation)).unlink([column.id]).done(function() {
+ if (column.is_empty()) {
+ var index = self.widgets.indexOf(column);
+ self.widgets.splice(index,1);
+ column.destroy();
+ } else {
+ self.do_reload();
+ }
+ });
+ },
-});
+ reload_record: function (record) {
+ var self = this;
+ this.dataset.read_ids([record.id], this.fields_keys.concat(['__last_update'])).done(function(records) {
+ if (records.length) {
+ record.update(records[0]);
+ self.postprocess_m2m_tags(record);
+ } else {
+ record.destroy();
+ }
+ });
+ },
+ add_record_to_column: function (event) {
+ var self = this;
+ var column = event.target;
+ var record = event.data.record;
+ var data = {};
+ data[this.group_by_field] = event.target.id;
+ this.dataset.write(record.id, data, {}).done(function () {
+ if (!self.isDestroyed()) {
+ self.reload_record(record);
+ self.resequence_column(column);
+ }
+ });
+ },
-odoo.define(function (require) {
+ update_record: function(event) {
+ var self = this;
+ var record = event.target;
+ return this.dataset.write(record.id, event.data)
+ .done(function () {
+ if (!self.isDestroyed()) {
+ self.reload_record(record);
+ }
+ });
+ },
-var core = require('web.core');
-var data = require('web.data');
-var web_client = require('web.web_client');
-var kanban_common = require('web_kanban.common');
-var KanbanView = require('web_kanban.KanbanView');
+ column_add_record: function (event) {
+ var self = this;
+ var column = event.target;
+ var context = {};
+ context['default_' + this.group_by_field] = column.value;
+ var name = event.data.value;
+ this.dataset.name_create(name, context).then(function on_success (data) {
+ add_record(data[0]);
+ }, function on_fail (event) {
+ event.preventDefault();
+ var popup = new form_common.SelectCreatePopup(this);
+ popup.select_element(
+ self.dataset.model,
+ {
+ title: _t("Create: "),
+ initial_view: "form",
+ disable_multiple_selection: true
+ },
+ [],
+ {"default_name": name}
+ );
+ popup.on("elements_selected", self, function(element_ids) {
+ add_record(element_ids[0]);
+ });
+ });
-var KanbanGroup = kanban_common.KanbanGroup;
-var _t = core._t;
+ function add_record(id) {
+ self.dataset.add_ids([id], -1);
+ self.dataset.read_ids([id], self.fields_keys.concat(['__last_update'])).done(function(record) {
+ column.add_record(record[0], {position: 'before'});
+ });
+ }
+ },
+
+ add_new_column: function (event) {
+ var self = this;
+ var model = new Model(this.relation, this.search_context);
+ model.call('create', [{name: event.data.value}], {
+ context: this.search_context,
+ }).then(function (id) {
+ var dataset = new data.DataSetSearch(self, self.dataset.model, self.dataset.get_context(), []);
+ var group_data = {
+ records: [],
+ title: event.data.value,
+ id: id,
+ attributes: {folded: false},
+ dataset: dataset,
+ values: {},
+ };
+ var options = self.get_column_options();
+ var record_options = _.clone(self.record_options);
+ var column = new KanbanColumn(self, group_data, options, record_options);
+ column.insertBefore(self.$('.o_column_quick_create'));
+ self.widgets.push(column);
+ });
+ },
-KanbanView.include({
- do_add_group: function() {
+ load_more: function (event) {
var self = this;
- self.do_action({
- name: _t("Add column"),
- res_model: self.group_by_field.relation,
- views: [[false, 'form']],
- type: 'ir.actions.act_window',
- target: "new",
- context: self.dataset.get_context(),
- flags: {
- action_buttons: true,
+ var column = event.target;
+ var offset = column.offset + this.limit;
+ return this.load_records(offset, column.dataset).then(function (result) {
+ _.each(result.records, function (r) {
+ column.add_record(r, {no_update: true});
+ });
+ column.offset += self.limit;
+ column.remaining = Math.max(column.remaining - self.limit, 0);
+ column.update_column();
+ self.postprocess_m2m_tags(column.records);
+ });
+ },
+
+ call_method: function (event) {
+ var data = event.data;
+ this.dataset.call(data.method, data.params).then(function() {
+ if (data.callback) {
+ data.callback();
}
});
- var am = web_client.action_manager;
- var form = am.dialog_widget.views.form.controller;
- form.on("on_button_cancel", am.dialog, am.dialog.close);
- form.on('record_created', self, function(r) {
- (new data.DataSet(self, self.group_by_field.relation)).name_get([r]).done(function(new_record) {
- am.dialog.close();
- var domain = self.dataset.domain.slice(0);
- domain.push([self.group_by, '=', new_record[0][0]]);
- var dataset = new data.DataSetSearch(self, self.dataset.model, self.dataset.get_context(), domain);
- var datagroup = {
- get: function(key) {
- return this[key];
- },
- value: new_record[0],
- length: 0,
- };
- var new_group = new KanbanGroup(self, [], datagroup, dataset);
- self.do_add_groups([new_group]).done(function() {
- $(window).scrollTo(self.groups.slice(-1)[0].$el, { axis: 'x' });
+ }
+});
+
+function qweb_add_if(node, condition) {
+ if (node.attrs[QWeb.prefix + '-if']) {
+ condition = _.str.sprintf("(%s) and (%s)", node.attrs[QWeb.prefix + '-if'], condition);
+ }
+ node.attrs[QWeb.prefix + '-if'] = condition;
+}
+
+function transform_qweb_template (node, fvg, many2manys) {
+ // Process modifiers
+ if (node.tag && node.attrs.modifiers) {
+ var modifiers = JSON.parse(node.attrs.modifiers || '{}');
+ if (modifiers.invisible) {
+ qweb_add_if(node, _.str.sprintf("!kanban_compute_domain(%s)", JSON.stringify(modifiers.invisible)));
+ }
+ }
+ switch (node.tag) {
+ case 'field':
+ var ftype = fvg.fields[node.attrs.name].type;
+ ftype = node.attrs.widget ? node.attrs.widget : ftype;
+ if (ftype === 'many2many') {
+ if (_.indexOf(many2manys, node.attrs.name) < 0) {
+ many2manys.push(node.attrs.name);
+ }
+ node.tag = 'div';
+ node.attrs['class'] = (node.attrs['class'] || '') + ' oe_form_field oe_tags o_kanban_tags';
+ } else if (fields_registry.contains(ftype)) {
+ // do nothing, the kanban record will handle it
+ } else {
+ node.tag = QWeb.prefix;
+ node.attrs[QWeb.prefix + '-esc'] = 'record.' + node.attrs.name + '.value';
+ }
+ break;
+ case 'button':
+ case 'a':
+ var type = node.attrs.type || '';
+ if (_.indexOf('action,object,edit,open,delete,url'.split(','), type) !== -1) {
+ _.each(node.attrs, function(v, k) {
+ if (_.indexOf('icon,type,name,args,string,context,states,kanban_states'.split(','), k) != -1) {
+ node.attrs['data-' + k] = v;
+ delete(node.attrs[k]);
+ }
});
- });
+ if (node.attrs['data-string']) {
+ node.attrs.title = node.attrs['data-string'];
+ }
+ if (node.attrs['data-icon']) {
+ node.children = [{
+ tag: 'img',
+ attrs: {
+ src: session.prefix + '/web/static/src/img/icons/' + node.attrs['data-icon'] + '.png',
+ width: '16',
+ height: '16'
+ }
+ }];
+ }
+ if (node.tag == 'a' && node.attrs['data-type'] != "url") {
+ 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++) {
+ transform_qweb_template(node.children[i], fvg, many2manys);
+ }
+ }
+}
+
+var One2ManyKanbanView = KanbanView.extend({
+ render_pager: function($node, options) {
+ options = _.extend(options || {}, {
+ single_page_hidden: true,
});
+ this._super($node, options);
},
});
+core.view_registry.add('kanban', KanbanView);
+core.one2many_view_registry.add('kanban', One2ManyKanbanView);
+
+return KanbanView;
+
});
+
diff --git a/addons/web_kanban/static/src/js/kanban_widgets.js b/addons/web_kanban/static/src/js/kanban_widgets.js
new file mode 100644
index 00000000000..29942075e79
--- /dev/null
+++ b/addons/web_kanban/static/src/js/kanban_widgets.js
@@ -0,0 +1,247 @@
+odoo.define('web_kanban.widgets', function (require) {
+"use strict";
+
+var core = require('web.core');
+var ProgressBar = require('web.ProgressBar');
+var pyeval = require('web.pyeval');
+var Registry = require('web.Registry');
+var session = require('web.session');
+var Widget = require('web.Widget');
+
+var QWeb = core.qweb;
+/**
+ * Interface to be implemented by kanban fields.
+ *
+ */
+var FieldInterface = {
+ /**
+ Constructor.
+ - parent: The widget's parent.
+ - field: A dictionary giving details about the field, including the current field's value in the
+ raw_value field.
+ - $node: The field <field> tag as it appears in the view, encapsulated in a jQuery object.
+ */
+ init: function(parent, field, $node) {},
+};
+
+/**
+ * Abstract class for classes implementing FieldInterface.
+ *
+ * Properties:
+ * - value: useful property to hold the value of the field. By default, the constructor
+ * sets value property.
+ *
+ */
+var AbstractField = Widget.extend(FieldInterface, {
+ /**
+ Constructor that saves the field and $node parameters and sets the "value" property.
+ */
+ init: function(parent, field, $node) {
+ this._super(parent);
+ this.field = field;
+ this.$node = $node;
+ this.options = pyeval.py_eval(this.$node.attr("options") || '{}');
+ this.set("value", field.raw_value);
+ },
+});
+
+var Priority = AbstractField.extend({
+ init: function(parent, field, $node) {
+ this._super.apply(this, arguments);
+ this.name = $node.attr('name');
+ },
+ prepare_priority: function() {
+ var self = this;
+ var selection = this.field.selection || [];
+ var init_value = selection && selection[0][0] || 0;
+ var data = _.map(selection.slice(1), function(element, index) {
+ var value = {
+ 'value': element[0],
+ 'name': element[1],
+ 'click_value': element[0],
+ };
+ if (index === 0 && self.get('value') == element[0]) {
+ value.click_value = init_value;
+ }
+ return value;
+ });
+ return data;
+ },
+ renderElement: function() {
+ this.priorities = this.prepare_priority();
+ var readonly = this.field && this.field.readonly;
+ if (readonly){
+ this.set('readonly', true);
+ }
+ this.$el = $(QWeb.render("Priority", {'widget': this}));
+ if (!readonly){
+ this.$el.on('click', 'a', this.do_action.bind(this));
+ }
+ },
+ do_action: function(event) {
+ event.preventDefault();
+ var $a = $(event.currentTarget);
+ var data = {};
+ data[this.name] = String($a.data('value'));
+ this.trigger_up('kanban_update_record', data);
+ },
+});
+
+var KanbanSelection = AbstractField.extend({
+
+ init: function(parent, field, $node) {
+ this._super.apply(this, arguments);
+ this.name = $node.attr('name');
+ this.parent = parent;
+ },
+ prepare_dropdown_selection: function() {
+ var self = this;
+ var data = [];
+ _.map(this.field.selection || [], function(res) {
+ var value = {
+ 'name': res[0],
+ 'tooltip': res[1],
+ 'state_name': res[1],
+ };
+ var leg_opt = self.options && self.options.states_legend || null;
+ if (leg_opt) {
+ var key = leg_opt[value.name];
+ var legend = self.parent.group_info[key];
+ if (legend) {
+ value.state_name = legend;
+ value.tooltip = legend;
+ }
+ }
+ if (res[0] == 'normal') { value.state_class = 'oe_kanban_status'; }
+ else if (res[0] == 'done') { value.state_class = 'oe_kanban_status oe_kanban_status_green'; }
+ else { value.state_class = 'oe_kanban_status oe_kanban_status_red'; }
+ data.push(value);
+ });
+ return data;
+ },
+ renderElement: function() {
+ var self = this;
+ this.states = this.prepare_dropdown_selection();
+
+ var state;
+ for(var i = 0 ; i < this.states.length ; i++) {
+ if(this.states[i].name === this.get('value')) {
+ state = this.states[i];
+ }
+ }
+
+ this.$el = $(QWeb.render("KanbanSelection", {'widget': this}));
+ this.$('a').first().find('span').removeClass().addClass(state.state_class);
+ this.$('ul li').show().filter(function() {
+ return ($(this).data('value') === state.name);
+ }).hide();
+
+ this.$('a').click(function (ev) {
+ ev.preventDefault();
+ });
+
+ this.$('li').click(this.set_kanban_selection.bind(this));
+ },
+ set_kanban_selection: function(e) {
+ e.preventDefault();
+ var self = this;
+ var $li = $(e.target).closest( "li" );
+ if ($li.length) {
+ var value = {};
+ value[self.name] = String($li.data('value'));
+ this.trigger_up('kanban_update_record', value, this);
+ }
+ },
+});
+
+var KanbanAttachmentImage = AbstractField.extend({
+ template: 'KanbanAttachmentImage',
+});
+
+
+/**
+ * Kanban widgets: ProgressBar
+ * options
+ * - editable: boolean if current_value is editable
+ * - current_value: get the current_value from the field that must be present in the view
+ * - max_value: get the max_value from the field that must be present in the view
+ * - title: title of the gauge, displayed on top of the gauge
+ * - on_change: action to call when cliking and setting a value
+ */
+var KanbanProgressBar = AbstractField.extend({
+ events: {
+ 'click': function() {
+ if(!this.readonly && this.progressbar.readonly) {
+ this.toggle_progressbar();
+ }
+ }
+ },
+
+ init: function (parent, field, node) {
+ this._super(parent, field, node);
+
+ var record = this.getParent().record;
+ this.progressbar = new ProgressBar(this, {
+ readonly: true,
+ value: record[this.options.current_value].raw_value,
+ max_value: record[this.options.max_value].raw_value,
+ title: this.options.title,
+ edit_max_value: this.options.edit_max_value,
+ });
+
+ this.readonly = !this.options.editable;
+ this.on_change = this.options.on_change;
+ },
+
+ start: function () {
+ var self = this;
+
+ var def = this.progressbar.appendTo('<div>').done(function() {
+ self.progressbar.$el.addClass(self.$el.attr('class'));
+ self.replaceElement(self.progressbar.$el);
+ });
+
+ return $.when(this._super(), def).then(function() {
+ if(!self.readonly) {
+ var parent = self.getParent();
+ self.progressbar.on('change:value change:max_value', self, function(e) {
+ var value = this.progressbar.get(this.progressbar.edit_max_value ? 'max_value' : 'value') || 0;
+ if(!isNaN(value)) {
+ var data = {
+ method: this.on_change,
+ params: [parent.id, value],
+ callback: self.proxy('toggle_progressbar'),
+ };
+ self.trigger_up('kanban_call_method', data);
+
+ // parent.view.dataset.call(this.on_change, [parent.id, value]).then(function() {
+ // self.toggle_progressbar();
+ // });
+ }
+ });
+ }
+ });
+ },
+
+ toggle_progressbar: function() {
+ this.progressbar.readonly = !this.progressbar.readonly;
+ var $div = $('<div/>').insertAfter(this.$el);
+ this.progressbar.replace($div);
+ this.setElement(this.progressbar.$el);
+ },
+});
+
+var fields_registry = new Registry();
+
+fields_registry
+ .add('priority', Priority)
+ .add('kanban_state_selection', KanbanSelection)
+ .add("attachment_image", KanbanAttachmentImage)
+ .add('progress', KanbanProgressBar);
+
+return {
+ AbstractField: AbstractField,
+ registry: fields_registry,
+};
+
+});
diff --git a/addons/web_kanban/static/src/less/kanban_dashboard.less b/addons/web_kanban/static/src/less/kanban_dashboard.less
index 3315beef9eb..61df77edcd0 100644
--- a/addons/web_kanban/static/src/less/kanban_dashboard.less
+++ b/addons/web_kanban/static/src/less/kanban_dashboard.less
@@ -1,7 +1,7 @@
-.oe_kanban_view {
+.o_kanban_view {
&.o_kanban_mobile {
- .oe_kanban_record {
+ .o_kanban_record {
width: 400px;
}
span {
@@ -14,8 +14,6 @@
&.o_kanban_dashboard {
- @odoo-brand-optional: #21b799;
-
.o_visible {
width: 100%;
}
@@ -43,8 +41,8 @@
margin-right: 0px !important;
}
+
.oe_kanban_colorpicker {
- min-height: 21px;
li {
height: 0px;
@@ -52,45 +50,37 @@
}
}
- .oe_kanban_record {
- padding: 0;
- position: relative;
- margin: 10px;
-
- // @media (max-width: @grid-float-breakpoint) {
- // margin: 10px !important;
- // }
- }
-
- // if invisible, it will no take more than its original height
+ // If invisible, elem will no take more than its original height
a, span {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
position: relative;
- width: 100%;
display: block;
}
+ .o_kanban_record {
+ padding: 0;
+ position: relative;
+ margin: 4px 8px;
+ }
+
a {
- // color: @odoo-brand-optional;
+ color: @odoo-brand-optional;
}
.o_kanban_card_header {
- display: flex;
- display: -webkit-flex;
+ .o-flex-display();
background-color: lightgrey;
position: relative;
.o_kanban_card_header_title {
- -webkit-flex: 3 0 0;
- flex: 3 0 0;
- padding: 8px;
+ .o-flex(3, 0, 0);
+ padding: 8px 16px;
.o_primary {
- // color: @odoo-brand-optional;
- font-variant: small-caps;
- font-size: large;
+ color: @odoo-brand-optional;
+ font-weight: 700;
}
.o_secondary {
@@ -98,12 +88,11 @@
}
.o_kanban_manage_button_section {
- -webkit-flex: 1 0 0;
- flex: 1 0 0;
+ .o-flex(1, 0, 0);
padding: 16px;
.o_kanban_manage_toggle_button {
- text-align: center;
+ text-align: right;
}
}
}
@@ -129,6 +118,7 @@
.o_kanban_card_manage_pane {
display: inline-block;
vertical-align: top;
+ padding: 0 8px;
}
.o_kanban_card_manage_section {
@@ -145,6 +135,7 @@
}
.o_kanban_card_manage_settings {
+ text-align: right;
padding: 8px;
border-color: lightgrey;
diff --git a/addons/web_kanban/static/src/less/kanban_view.less b/addons/web_kanban/static/src/less/kanban_view.less
new file mode 100644
index 00000000000..4d7a6221dbf
--- /dev/null
+++ b/addons/web_kanban/static/src/less/kanban_view.less
@@ -0,0 +1,500 @@
+@o-kanban-record-margin: 4px;
+
+.o_kanban_view {
+
+ .o-flex-display();
+ .o-align-content(stretch);
+ @media (max-width: @grid-float-breakpoint) {
+ padding: 0px;
+ }
+
+ .o_kanban_quick_create {
+ background-color: white;
+ margin: @o-kanban-record-margin;
+ box-shadow: 0px 0px 1px 1px lighten(@odoo-main-text-color, 10%);
+ padding: 3px;
+ input {
+ width: 100%;
+ margin: 4px 0;
+ }
+ }
+
+ .o_kanban_record {
+ min-width: 150px;
+ background-color: white;
+ margin: 4px 4px 8px 4px;
+ box-shadow: 0px 0px 1px 1px lighten(@odoo-main-text-color, 10%);
+ padding: 8px;
+
+ &.o_record_dragged {
+ background-color: @odoo-main-text-color;
+ }
+
+ &.oe_kanban_global_click, &.oe_kanban_global_click_edit {
+ cursor: pointer;
+ }
+
+ ul {
+ list-style-type: none;
+ padding: 0;
+ }
+
+ &.o_kanban_two_column {
+ .o-flex-display();
+
+ .oe_kanban_details {
+ position: relative;
+ display: inline-block;
+ .o-flex(1, 1, auto);
+ width: 0;
+ }
+ }
+
+ &.o_kanban_two_column_tags {
+ .o-flex-display();
+ .o-flex-flow(row, wrap);
+
+ .o_kanban_tags_section {
+ .o-flex(1, 1, 100%);
+ }
+ .o_kanban_image {
+ .o-flex(1, 1, 25%);
+ margin-right: 0;
+ > img {
+ box-shadow: none;
+ }
+ }
+ .oe_kanban_details {
+ position: relative;
+ .o-flex(1, 1, 75%);
+ ul {
+ margin-bottom: 0;
+ }
+ }
+ }
+
+ .o_kanban_title {
+ font-weight: bold;
+ margin-bottom: 3px;
+ }
+
+ .o_kanban_image {
+ .o-flex(0, 0, auto);
+ margin-right: 8px;
+ text-align: center;
+
+ img {
+ width: 64px;
+ height: 64px;
+ box-shadow: none;
+ }
+
+ }
+
+ .o_kanban_button {
+ margin-top: 15px;
+
+ > button, > a {
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ }
+ }
+
+ &.ui-sortable-helper {
+ transform: rotate(3deg);
+ opacity: 0.9,
+ }
+
+ .o_dropdown_kanban {
+ float: right;
+
+ // Open the dropdown a the left side of the dropdown toggle
+ > .dropdown-menu {
+ left: auto;
+ right: 0;
+ padding: 3px;
+ }
+
+ > a {
+ padding: 3px;
+ color: @odoo-main-text-color;
+ }
+ &.open {
+ visibility: visible;
+ }
+ }
+
+ .o_kanban_footer {
+ .o-flex-display();
+ .o-justify-content(space-between);
+ > * {
+ flex: none;
+ }
+ }
+ &:hover {
+ .o_dropdown_kanban {
+ visibility: visible;
+ }
+ }
+ .o_dropdown_kanban {
+ @media (max-width: @grid-float-breakpoint) {
+ visibility: visible;
+ }
+ }
+ }
+
+ &.o_kanban_ungrouped {
+ .o-flex-flow(row, wrap);
+ .o-justify-content(flex-start);
+ padding: @o-kanban-record-margin @odoo-horizontal-padding - @o-kanban-record-margin;
+
+ @media (max-width: @grid-float-breakpoint) {
+ padding: 0;
+ }
+
+ .o_kanban_record {
+ .o-flex(1, 1, auto);
+ width: 320px;
+ @media (max-width: @grid-float-breakpoint) {
+ margin: 0 0 1px 0;
+ width: 100vw;
+ box-shadow: none;
+ }
+ }
+
+ .o_kanban_ghost {
+ height: 0;
+ min-height: 0 !important; // to prevent view writers to override this height
+ visibility: hidden;
+ margin-top: 0;
+ margin-bottom: 0;
+ padding: 0;
+ }
+
+ }
+
+ &.o_kanban_grouped {
+ min-height: 100%;
+ padding: 0 @odoo-horizontal-padding - @o-kanban-record-margin;
+ .o_kanban_record {
+ width: 300px;
+
+ &.o_kanban_small {
+ width: 240px;
+ }
+ }
+ }
+
+ .o_kanban_group {
+ .o-flex(0, 0, auto);
+ margin: 0 4px;
+
+ &.o_kanban_dragged {
+ background-color: @odoo-main-text-color;
+ .o_kanban_record {
+ visibility: hidden;
+ }
+ }
+
+ .o_kanban_header + .o_kanban_record {
+ margin-top: 0; // no margin top from the first card after kanban_header
+ }
+
+ .o_kanban_header {
+ color: white;
+ padding: 0 4px;
+ height: 50px;
+ line-height: 2.2;
+ cursor: move;
+ .o-flex-display();
+ .o_column_unfold {
+ display: none;
+ }
+ .o_column_title {
+ font-size: 18px;
+ font-weight: 300;
+ .o-flex(1, 1, auto);
+ white-space: nowrap;
+ padding-top: 5px;
+ }
+
+ .o-kanban-icon() {
+ // Share the style of `.o_kanban_quick_add` and `o_kanban_config`.
+ height: 50px;
+ width: 50px;
+ line-height: 1.8;
+ text-align: center;
+ color: white;
+ padding: 8px;
+ font-size: 22px;
+ cursor: pointer;
+ }
+
+ .o_kanban_quick_add i {
+ .o-kanban-icon;
+ &:hover {
+ background-color: @odoo-brand-optional;
+ }
+ }
+ .o_kanban_config i {
+ .o-kanban-icon;
+ &:hover {
+ background-color: darken(@gray-light, 10%);
+ }
+ }
+
+ .o_kanban_number {
+ color: @odoo-main-text-color;
+ text-align: center;
+ }
+ }
+
+ .o_kanban_record {
+ &.o_kanban_dragged {
+ > * {
+ visibility: hidden;
+ }
+ background-color: @odoo-main-text-color;
+ }
+ }
+
+ &.o_column_folded {
+ position: relative;
+ border-right: 1px solid @odoo-main-text-color;
+ margin: 0;
+
+ .o_column_title {
+ line-height: 1.3;
+ text-transform: uppercase;
+ transform-origin: left bottom;
+ transform: rotate(90deg);
+ top: 40px;
+ left: 15px;
+ position: absolute;
+ }
+ > .o_kanban_record, .o_kanban_quick_add, .o_kanban_config, .o_kanban_load_more {
+ display: none;
+ }
+ &:hover {
+ cursor: pointer;
+ background-color: darken(@gray-light, 10%);
+ }
+ .o_column_unfold {
+ display: block;
+ padding: 0 10px;
+
+ > i {
+ font-size: 22px;
+ padding-top: 15px;
+ }
+
+ }
+ background-color: @gray-light;
+ }
+
+ .o_kanban_load_more {
+ text-align: center;
+ a {
+ color: white;
+ font-weight: 300;
+ }
+ }
+ }
+
+ .oe_kanban_color_0 {
+ background-color: #FFFFFF;
+ color: #5a5a5a;
+ }
+ .oe_kanban_color_1 {
+ background-color: #d8d8d8;
+ color: #5e5e5e;
+ }
+ .oe_kanban_color_2 {
+ background-color: #e5d8e3;
+ color: #7a3737;
+ }
+ .oe_kanban_color_3 {
+ background-color: #ece9c2;
+ color: #756832;
+ }
+ .oe_kanban_color_4 {
+ background-color: #dee180;
+ color: #5d6937;
+ }
+ .oe_kanban_color_5 {
+ background-color: #abd4cc;
+ color: #1a7759;
+ }
+ .oe_kanban_color_6 {
+ background-color: #b8e3e8;
+ color: #1a5d83;
+ }
+ .oe_kanban_color_7 {
+ background-color: #f4ddab;
+ color: #5e5e5e;
+ }
+ .oe_kanban_color_8 {
+ background-color: #7f637d;
+ color: #a5a5a5;
+ }
+ .oe_kanban_color_9 {
+ background-color: #d8c5d5;
+ color: #5e5e5e;
+ }
+ .oe_kanban_color_10 {
+ background-color: #46C265;
+ color: #639B89;
+ }
+
+ .oe_tags {
+ display: block;
+ }
+ .o_kanban_tags {
+
+ margin-left: -8px;
+
+ .o_tag{
+ width: 50px;
+ height: 9px;
+ display: inline-block;
+ vertical-align: top;
+ }
+ }
+ .o_kanban_footer {
+ width: 100%;
+ }
+ .oe_kanban_avatar {
+ border-radius: 12px;
+ border: 1px solid @odoo-main-color-muted;
+ }
+
+ .o_progressbar {
+ .o_progressbar_title {
+ width: 20%;
+ }
+ .o_progress {
+ width: 60%;
+ height: 15px;
+ }
+ .o_progressbar_value {
+ width: 20%;
+ text-align: right;
+ }
+ }
+
+ .o_kanban_attachment_image {
+ // The image should take the hole card
+ margin: -8px;
+ > img {
+ width: 100%;
+ }
+ }
+}
+
+.oe_kanban_colorpicker {
+ li {
+ float: left;
+ &:first-child a {
+ border: 1px solid #ccc;
+ }
+
+ a {
+ width: 15px;
+ height: 16px;
+ display: inline-block;
+ border: 1px solid white;
+ }
+ }
+}
+
+.o_dropdown_kanban {
+ visibility: hidden;
+}
+
+.oe_kanban_avatar_smallbox {
+ height: 40px;
+ width: 40px;
+ box-shadow: 0 1px 4px @gray-light;
+ // border: 1px solid
+ // border-color: #e5e5e5 #dbdbdb #d2d2d2
+ // @include radius(3px)
+ // @include box-shadow(0 1px 2px rgba(0,0,0,0.2))
+}
+
+.o_kanban_shadow {
+ background-color: @odoo-main-text-color;
+ miw-width: 100px;
+}
+
+.o_column_quick_create {
+ .o-flex(0, 0, auto);
+ margin: 0;
+ padding: 8px;
+ position: relative;
+ background-color: @odoo-main-text-color;
+ cursor: pointer;
+
+ &:hover {
+ background-color: darken(@gray-light, 10%);
+ }
+ .o_column_header {
+ .o_kanban_add_column {
+ padding: 0 10px;
+ color: white;
+
+ > i {
+ font-size: 22px;
+ padding-top: 7px;
+ }
+ }
+ .o_kanban_title {
+ font-size: 18px;
+ font-weight: 300;
+ white-space: nowrap;
+ color: @gray-lighter;
+ text-transform: uppercase;
+ transform-origin: left bottom;
+ transform: rotate(90deg);
+ top: 40px;
+ left: 15px;
+ position: absolute;
+ }
+ }
+ .o_kanban_quick_create {
+ display: none;
+ width: 180px;
+ }
+}
+
+.oe_kanban_footer_left {
+ float: left;
+}
+
+.oe_kanban_bottom_right {
+ float: right;
+}
+
+.oe_kanban_bottom_left {
+ float: left;
+}
+
+.oe_kanban_status {
+ display: inline-block;
+ height: 12px;
+ width: 12px;
+ border-radius: 6px;
+
+ background-color: @odoo-brand-secondary;
+
+ &.oe_kanban_status_green {
+ background-color: @brand-success;
+ }
+ &.oe_kanban_status_red {
+ background-color: @brand-danger;
+ }
+}
+
+.o_form_field_one2many .oe_view_nocontent {
+ display: none;
+} \ No newline at end of file
diff --git a/addons/web_kanban/static/src/xml/web_kanban.xml b/addons/web_kanban/static/src/xml/web_kanban.xml
index 0a7bbcdcffb..497b0696025 100644
--- a/addons/web_kanban/static/src/xml/web_kanban.xml
+++ b/addons/web_kanban/static/src/xml/web_kanban.xml
@@ -1,90 +1,72 @@
<template>
-<t t-name="KanbanView">
- <div class="oe_kanban_view">
- <div class="oe_kanban_buttons"/>
- <table class="oe_kanban_groups">
- <tr class="oe_kanban_groups_headers">
- <td class="oe_kanban_dummy_cell"><div/></td>
- </tr>
- <tr class="oe_kanban_groups_records">
- <td class="oe_kanban_dummy_cell"><div/></td>
- </tr>
- </table>
- </div>
-</t>
+
<t t-name="KanbanView.buttons">
<t t-if="display">
- <div class="oe_kanban_buttons">
- <button type="button" class="oe_kanban_button_new btn btn-primary btn-sm">
+ <div>
+ <button type="button" class="btn btn-primary btn-sm o-kanban-button-new">
<t t-esc="widget.options.create_text || _t('Create')"/>
</button>
- <span t-if="widget.is_action_enabled('group_create')" class="oe_alternative" style="display: none">
- <span class="oe_fade">or</span>
- <div class="oe_bounce_container">
- <a href="#" class="oe_kanban_add_column text-info">Add a new column</a>
- </div>
- </span>
</div>
</t>
</t>
-<t t-name="KanbanView.group_header">
- <td class="oe_kanban_group_header">
- <t t-if="widget.view.group_by">
- <t t-set="parent" t-value="(widget.getParent())"/>
- <div class="oe_kanban_header oe_semantic_html_override">
- <t t-if="widget.view._is_quick_create_enabled()">
- <div><i class="oe_kanban_add fa fa-plus" title="Quick create"/></div>
- </t>
- <div class="oe_dropdown_toggle oe_dropdown_kanban">
- <div class="oe_kanban_group_length">
- <span class="oe_tag">
- <t t-if="widget.group.get('length') &gt; 99"> 99+ </t><t t-if="widget.group.get('length') &lt;= 99"> <t t-esc="widget.group.get('length')"/> </t>
- </span>
- </div>
- <i class="fa fa-bars fa-lg"/>
- <ul class="oe_dropdown_menu oe_kanban_group_dropdown">
- <li><a data-action="toggle_fold" href="#">Fold</a></li>
- <t t-if="widget.view.grouped_by_m2o and widget.value">
- <li t-if="parent &amp;&amp; parent.is_action_enabled('group_edit')"><a data-action="edit" href="#">Edit</a></li>
- <li t-if="parent &amp;&amp; parent.is_action_enabled('group_delete')"><a data-action="delete" href="#">Delete</a></li>
- </t>
- </ul>
- </div>
- <div class="oe_fold_column">
- <div t-attf-class="oe_kanban_group_title #{widget.undefined_title ? 'oe_kanban_group_title_undefined' : ''}">
- <div class="oe_kanban_group_title_text" t-att-title="widget.title"><t t-esc="widget.title"/></div>
- </div>
- <div class="oe_kanban_group_length oe_tag">
- <t t-if="widget.group.get('length') &gt; 99"> 99+ </t><t t-if="widget.group.get('length') &lt;= 99"> <t t-esc="widget.group.get('length')"/> </t>
- </div>
- </div>
- <span t-if="widget.title" class="oe_kanban_group_title_vertical">
- <t t-esc="widget.title"/>
- </span>
- </div>
- </t>
- <t t-if="! widget.view.group_by &amp;&amp; widget.view._is_quick_create_enabled()">
- <span class="oe_kanban_no_group_qc_placeholder"/>
- </t>
- </td>
+
+<t t-name="KanbanView.Group">
+ <div class="o_kanban_group" t-att-data-id="widget.id">
+ <div class="o_kanban_header" t-att-title="widget.data_records.length + ' records'">
+ <span class="o_column_title"><t t-esc="widget.title"/></span>
+ <span class="o_column_unfold"><i class="fa fa-arrows-h"/></span>
+ <span class="o_kanban_config dropdown">
+ <a class="dropdown-toggle" data-toggle="dropdown" href="#"><i class="fa fa-gear"/></a>
+ <ul class="dropdown-menu" role="menu">
+ <li><a class="o_kanban_toggle_fold" href="#">Fold</a></li>
+ <t t-if="widget.grouped_by_m2o">
+ <li t-if="widget.editable and widget.id"><a class="o_column_edit" href="#">Edit</a></li>
+ <li t-if="widget.deletable and widget.id"><a class="o_column_delete" href="#">Delete</a></li>
+ </t>
+ </ul>
+ </span>
+ <t t-if="widget.quick_create">
+ <span class="o_kanban_quick_add"><i class="fa fa-plus"/></span>
+ </t>
+ </div>
+ <div t-if="widget.remaining > 0" class="o_kanban_load_more">
+ <t t-call="KanbanView.LoadMore"/>
+ </div>
+ </div>
+</t>
+
+<t t-name="KanbanView.LoadMore">
+ <a href="#">Load more... (<t t-esc="widget.remaining"/> remaining)</a>
</t>
-<t t-name="KanbanView.group_records_container">
- <td class="oe_kanban_column">
- <div class="oe_kanban_group_list_header"/>
- <div class="oe_kanban_column_cards"/>
- <div class="oe_kanban_folded_column_cards"/>
- <div class="oe_kanban_show_more">
- <button class="oe_button">Show more... (<span class="oe_kanban_remaining"></span> remaining)</button>
+
+<t t-name="KanbanView.ColumnQuickCreate">
+ <div class="o_column_quick_create">
+ <div class="o_column_header">
+ <span class="o_kanban_add_column"><i class="fa fa-chevron-right"/></span>
+ <span class="o_kanban_title">Add new Column</span>
</div>
- </td>
+ <div class="o_kanban_quick_create">
+ <input type="text" placeholder="Add"/>
+ <button class="btn btn-primary o_kanban_add">Add</button>
+ <button class="btn btn-default o_kanban_cancel">Cancel</button>
+ </div>
+ </div>
</t>
+
<t t-name="KanbanView.record">
- <div class="oe_fold_column oe_kanban_record">
- <t t-raw="content"/>
+ <t t-raw="widget.content"/>
+</t>
+
+<t t-name="KanbanView.QuickCreate">
+ <div class="o_kanban_quick_create">
+ <input type="text" placeholder="Add"/>
+ <button class="btn btn-primary o_kanban_add">Add</button>
+ <button class="btn btn-default o_kanban_cancel">Cancel</button>
</div>
</t>
+
<t t-name="KanbanColorPicker">
- <li t-foreach="widget.view.number_of_color_schemes" t-as="color">
+ <li t-foreach="10" t-as="color">
<a href="#" t-att-data-color="color_index" t-attf-class="oe_kanban_color_#{color}"/>
</li>
</t>
@@ -98,11 +80,13 @@
</t>
</div>
<t t-name="KanbanView.nocontent">
- <div class="oe_view_nocontent" style="position:absolute;">
- <div class="oe_view_nocontent_bg"></div>
- <div class="oe_view_nocontent_content">
- <t t-raw="content"/>
- </div>
+ <div class="oe_view_nocontent">
+ <t t-raw="content"/>
+ </div>
+</t>
+<t t-name="KanbanAttachmentImage">
+ <div class="o_kanban_attachment_image">
+ <img t-att-src="'/web/binary/image?model=ir.attachment&amp;field=datas&amp;id=' + widget.field.raw_value[0]"/>
</div>
</t>
</template>
diff --git a/addons/web_kanban/views/web_kanban.xml b/addons/web_kanban/views/web_kanban.xml
index b9fb5dff577..f383254636d 100644
--- a/addons/web_kanban/views/web_kanban.xml
+++ b/addons/web_kanban/views/web_kanban.xml
@@ -3,11 +3,14 @@
<data>
<template id="assets_backend" name="web_kanban assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
- <link rel="stylesheet" href="/web_kanban/static/src/css/kanban.css"/>
<link rel="stylesheet" href="/web_kanban/static/src/less/kanban_dashboard.less"/>
+ <link rel="stylesheet" href="/web_kanban/static/src/less/kanban_view.less"/>
+ <script type="text/javascript" src="/web_kanban/static/src/js/kanban_record.js"></script>
+ <script type="text/javascript" src="/web_kanban/static/src/js/kanban_quick_create.js"></script>
+ <script type="text/javascript" src="/web_kanban/static/src/js/kanban_column.js"></script>
<script type="text/javascript" src="/web_kanban/static/src/js/kanban_view.js"></script>
- <script type="text/javascript" src="/web_kanban/static/src/js/kanban_common.js"></script>
+ <script type="text/javascript" src="/web_kanban/static/src/js/kanban_widgets.js"></script>
<script type="text/javascript" src="/web_kanban/static/src/js/compatibility.js"></script>
</xpath>
</template>
diff --git a/addons/web_kanban_gauge/static/src/js/kanban_gauge.js b/addons/web_kanban_gauge/static/src/js/kanban_gauge.js
index 7ffd021af4b..0a9f3a96b44 100644
--- a/addons/web_kanban_gauge/static/src/js/kanban_gauge.js
+++ b/addons/web_kanban_gauge/static/src/js/kanban_gauge.js
@@ -2,10 +2,10 @@ odoo.define('web_kanban_gauge.widget', function (require) {
"use strict";
var core = require('web.core');
-var kanban_common = require('web_kanban.common');
+var kanban_widgets = require('web_kanban.widgets');
-var AbstractField = kanban_common.AbstractField;
-var fields_registry = kanban_common.registry;
+var AbstractField = kanban_widgets.AbstractField;
+var fields_registry = kanban_widgets.registry;
var _t = core._t;
/**
diff --git a/addons/web_tests/tests/test_ui.py b/addons/web_tests/tests/test_ui.py
index 8f00a6859a4..43a35a7cfc2 100644
--- a/addons/web_tests/tests/test_ui.py
+++ b/addons/web_tests/tests/test_ui.py
@@ -11,4 +11,4 @@ class TestUi(openerp.tests.HttpCase):
def test_03_js_public(self):
self.phantom_js('/',"console.log('ok')","console")
def test_04_js_admin(self):
- self.phantom_js('/web',"console.log('ok')","openerp.client.action_manager.inner_widget", login='admin')
+ self.phantom_js('/web',"console.log('ok')","odoo.__DEBUG__.services['web.web_client'].action_manager", login='admin') \ No newline at end of file
diff --git a/addons/website/static/src/css/website.backend.css b/addons/website/static/src/css/website.backend.css
index 24879793303..91b3e7c01ea 100644
--- a/addons/website/static/src/css/website.backend.css
+++ b/addons/website/static/src/css/website.backend.css
@@ -1,7 +1,7 @@
-.oe_WidgetWebsiteButton.danger .oe_publish {
- display: none;
+.oe_stat_button .o_stat_info:not(.published) > .o_stat_text.oe_publish {
+ display: none;
}
-.oe_WidgetWebsiteButton.success .oe_unpublish {
+.oe_stat_button .o_stat_info.published > .o_stat_text.oe_unpublish {
display: none;
}
.oe_form_field_html_frame iframe {
diff --git a/addons/website/static/src/js/website.backend.js b/addons/website/static/src/js/website.backend.js
index b1920dc4cab..d1bb6c2f5b0 100644
--- a/addons/website/static/src/js/website.backend.js
+++ b/addons/website/static/src/js/website.backend.js
@@ -9,10 +9,13 @@ var form_widgets = require('web.form_widgets'); // required to guarantee that
var WidgetWebsiteButton = form_common.AbstractField.extend({
template: 'WidgetWebsiteButton',
render_value: function() {
+ // Hack to replace false value by unpublished because falsy form fields
+ // have classname o_form_field_empty and are hidden
+ if (!this.get_value()) {
+ this.set_value('unpublished');
+ }
this._super();
- this.$()
- .toggleClass("success", this.get_value())
- .toggleClass("danger", !this.get_value());
+ this.$el.toggleClass("published", this.get_value() === true);
if (this.node.attrs.class) {
this.$el.addClass(this.node.attrs.class);
}
diff --git a/addons/website/static/src/xml/website.backend.xml b/addons/website/static/src/xml/website.backend.xml
index 24f8c825816..826e29e261c 100644
--- a/addons/website/static/src/xml/website.backend.xml
+++ b/addons/website/static/src/xml/website.backend.xml
@@ -1,12 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
- <t t-name="WidgetWebsiteButton">
- <div class="oe_WidgetWebsiteButton success">
- <strong class="oe_unpublish text-danger">Not<br/>Published</strong>
- <strong class="oe_publish text-success">Published</strong>
- </div>
- </t>
+ <div t-name="WidgetWebsiteButton" class="o_stat_info published">
+ <span class="o_stat_text oe_unpublish text-danger">Not Published</span>
+ <span class="o_stat_text oe_publish text-success">Published</span>
+ </div>
<t t-name="FieldTextHtmlFrame">
<div class="oe_form_field oe_form_field_html_frame oe_form_embedded_html" t-att-style="widget.node.attrs.style">
diff --git a/addons/website_blog/views/website_blog_views.xml b/addons/website_blog/views/website_blog_views.xml
index 8e43249eabf..c281a09ea10 100644
--- a/addons/website_blog/views/website_blog_views.xml
+++ b/addons/website_blog/views/website_blog_views.xml
@@ -52,8 +52,8 @@
<field name="arch" type="xml">
<form string="Blog Post">
<sheet>
- <div class="oe_right oe_button_box">
- <button class="oe_inline oe_stat_button" name="open_website_url"
+ <div class="oe_button_box" name="button_box">
+ <button class="oe_stat_button" name="open_website_url"
type="object" icon="fa-globe">
<field name="website_published" widget="website_button"/>
</button>
diff --git a/addons/website_crm_partner_assign/views/partner_grade.xml b/addons/website_crm_partner_assign/views/partner_grade.xml
index 0605e8b6887..d5f10f5bb87 100644
--- a/addons/website_crm_partner_assign/views/partner_grade.xml
+++ b/addons/website_crm_partner_assign/views/partner_grade.xml
@@ -8,8 +8,8 @@
<field name="inherit_id" ref="crm_partner_assign.view_partner_grade_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@class='oe_title']" position="before">
- <div class="oe_right oe_button_box">
- <button class="oe_inline oe_stat_button" name="open_website_url"
+ <div class="oe_button_box" name="button_box">
+ <button class="oe_stat_button" name="open_website_url"
type="object" icon="fa-globe">
<field name="website_published" widget="website_button"/>
</button>
diff --git a/addons/website_crm_score/static/src/js/display_filters.js b/addons/website_crm_score/static/src/js/display_filters.js
index 859ec6fd218..fc0eea59dda 100644
--- a/addons/website_crm_score/static/src/js/display_filters.js
+++ b/addons/website_crm_score/static/src/js/display_filters.js
@@ -1,10 +1,10 @@
odoo.define('website_crm_score.filters', function (require) {
"use strict";
-var common = require('web_kanban.common');
+var kanban_widgets = require('web_kanban.widgets');
-var Filters = common.AbstractField.extend({
+var Filters = kanban_widgets.AbstractField.extend({
/**
bnf grammar of a filter:
<filter> ::= <expr>
@@ -95,6 +95,6 @@ var Filters = common.AbstractField.extend({
}
});
-common.registry.add('filters', Filters);
+kanban_widgets.registry.add('filters', Filters);
});
diff --git a/addons/website_crm_score/views/marketing.xml b/addons/website_crm_score/views/marketing.xml
index 2d5d873664c..0a34c2d8dca 100644
--- a/addons/website_crm_score/views/marketing.xml
+++ b/addons/website_crm_score/views/marketing.xml
@@ -65,8 +65,8 @@
<field name="arch" type="xml">
<form string="Scores">
<sheet>
- <div class="oe_right oe_button_box" name="buttons">
- <button class="oe_inline oe_stat_button" type="action"
+ <div class="oe_button_box" name="button_box">
+ <button class="oe_stat_button" type="action"
name="%(score_leads)d" icon="fa-tags"
>
<field string="Leads" name="leads_count" widget="statinfo"/>
diff --git a/addons/website_crm_score/views/sales.xml b/addons/website_crm_score/views/sales.xml
index 565c71501b9..08045f9e38e 100644
--- a/addons/website_crm_score/views/sales.xml
+++ b/addons/website_crm_score/views/sales.xml
@@ -41,14 +41,13 @@
<field name="model">crm.lead</field>
<field name="inherit_id" ref="crm.crm_case_form_view_leads" />
<field name="arch" type="xml">
- <!-- <xpath expr="//button[@class='oe_inline oe_stat_button']" position="after"> -->
- <xpath expr="//div[@name='buttons']" position="inside">
- <button class="oe_inline oe_stat_button" type="action"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" type="action"
name="%(website_crm_score_pageviews)d" icon="fa-tags"
context="{'search_default_lead_id': active_id, 'default_lead_id': active_id}">
<field string="Page views" name="pageviews_count" widget="statinfo"/>
</button>
- </xpath>
+ </div>
<field name="priority" position="after">
<field name="score" />
</field>
@@ -146,14 +145,14 @@
<field name="inherit_id" ref="sales_team.crm_team_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@class='oe_title']" position="before">
- <div class="oe_right oe_button_box" name="buttons">
- <button class="oe_inline oe_stat_button" type="action"
+ <div class="oe_button_box" name="button_box">
+ <button class="oe_stat_button" type="action"
name="%(crm_score_views_action_graph)d" icon="fa-tags"
context="{'search_default_team_id': active_id, 'search_default_unassigned': 1 }"
>
<field string="Unassigned leads" name="unassigned_leads" widget="statinfo"/>
</button>
- <button class="oe_inline oe_stat_button" type="action"
+ <button class="oe_stat_button" type="action"
name="%(crm_score_views_action_table)d" icon="fa-tags"
context="{'search_default_team_id': active_id}"
>
@@ -257,4 +256,4 @@
</record>
</data>
-</openerp> \ No newline at end of file
+</openerp>
diff --git a/addons/website_event/views/website_event_backend.xml b/addons/website_event/views/website_event_backend.xml
index ddfc26a0e24..10522b254a0 100644
--- a/addons/website_event/views/website_event_backend.xml
+++ b/addons/website_event/views/website_event_backend.xml
@@ -8,20 +8,20 @@
<field name="inherit_id" ref="event.view_event_form"/>
<field name="arch" type="xml">
<!-- add state field in header -->
- <xpath expr="//div[@class='oe_right oe_button_box']" position="inside">
+ <div name="button_box" position="inside">
<field name="website_url" invisible="1"/>
- <button class="oe_inline oe_stat_button" name="open_website_url"
+ <button class="oe_stat_button" name="open_website_url"
type="object" icon="fa-globe">
<field name="website_published" widget="website_button"/>
</button>
- </xpath>
+ </div>
<xpath expr="//field[@name='organizer_id']" position="after">
<field name="twitter_hashtag"/>
</xpath>
- <xpath expr="//div[@class='oe_right oe_button_box']/button" position="before">
+ <xpath expr="//div[@name='button_box']/button" position="before">
<button name="action_open_badge_editor"
type="object"
- class="oe_stat_button oe_inline"
+ class="oe_stat_button"
icon="fa-newspaper-o"
string="Badge"
help="Edit Event Badge">
diff --git a/addons/website_event_track/views/event_backend.xml b/addons/website_event_track/views/event_backend.xml
index 7eb6a103d7d..4ae03d65506 100644
--- a/addons/website_event_track/views/event_backend.xml
+++ b/addons/website_event_track/views/event_backend.xml
@@ -18,8 +18,8 @@
<i class="fa fa-bars fa-lg"/>
<ul class="oe_dropdown_menu">
<li><a t-att-href="record.website_url.value" type="url">View Track</a></li>
- <t t-if="widget.view.is_action_enabled('edit')"><li><a type="edit">Edit Track</a></li></t>
- <t t-if="widget.view.is_action_enabled('delete')"><li><a type="delete">Delete</a></li></t>
+ <t t-if="widget.editable"><li><a type="edit">Edit Track</a></li></t>
+ <t t-if="widget.deletable"><li><a type="delete">Delete</a></li></t>
<li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
</ul>
</div>
@@ -90,9 +90,9 @@
<field name="state" widget="statusbar" clickable="True"/>
</header>
<sheet string="Track">
- <div class="oe_right oe_button_box">
+ <div class="oe_button_box" name="button_box">
<field name="website_url" invisible="1"/>
- <button class="oe_inline oe_stat_button" name="open_website_url"
+ <button class="oe_stat_button" name="open_website_url"
type="object" icon="fa-globe">
<field name="website_published" widget="website_button"/>
</button>
@@ -310,20 +310,20 @@ Tracks define the agenda of your event. These can be a talk, a round table, a me
<field name="inherit_id" ref="event.view_event_form"/>
<field name="model">event.event</field>
<field name="arch" type="xml">
- <xpath expr="//div[@class='oe_right oe_button_box']" position="inside">
+ <div name="button_box" position="inside">
<button name="%(action_event_track_from_event)d"
type="action"
- class="oe_stat_button oe_inline"
+ class="oe_stat_button"
icon="fa-inbox">
<field name="count_tracks" widget="statinfo"/>
</button>
<button name="%(action_event_sponsor_from_event)d"
type="action"
- class="oe_stat_button oe_inline"
+ class="oe_stat_button"
icon="fa-users">
- <field name="count_sponsor" widget="statinfo" class="oe_inline" string="Sponsorships"/>
+ <field name="count_sponsor" widget="statinfo" string="Sponsorships"/>
</button>
- </xpath>
+ </div>
<xpath expr="//div[@class='oe_title']" position="inside">
<div name="event_checkboxes">
<field name="show_menu"/>
@@ -334,8 +334,6 @@ Tracks define the agenda of your event. These can be a talk, a round table, a me
<label for="show_track_proposal"/>
</div>
</xpath>
- <xpath expr="//div[@class='oe_right oe_button_box']" position="inside">
- </xpath>
</field>
</record>
diff --git a/addons/website_forum/views/res_users.xml b/addons/website_forum/views/res_users.xml
index f0de0cfe855..5844e53cb36 100644
--- a/addons/website_forum/views/res_users.xml
+++ b/addons/website_forum/views/res_users.xml
@@ -11,12 +11,12 @@
<field name="signature" position="after">
<field name="karma" string="Forum Karma"/>
</field>
- <xpath expr="//div[contains(@class, 'oe_right oe_button_box')]" position="inside">
- <button class="oe_inline oe_stat_button" name="open_website_url"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" name="open_website_url"
type="object" icon="fa-globe">
<field name="website_published" widget="website_button"/>
</button>
- </xpath>
+ </div>
</field>
</record>
diff --git a/addons/website_forum_doc/views/doc.xml b/addons/website_forum_doc/views/doc.xml
index 9a32603fcab..f45243445b8 100644
--- a/addons/website_forum_doc/views/doc.xml
+++ b/addons/website_forum_doc/views/doc.xml
@@ -41,8 +41,8 @@
<div class="oe_dropdown_toggle oe_dropdown_kanban" groups="base.group_user">
<i class="fa fa-bars fa-lg"/>
<ul class="oe_dropdown_menu">
- <li t-if="widget.view.is_action_enabled('edit')"><a type="edit">Edit Post</a></li>
- <li t-if="widget.view.is_action_enabled('delete')"><a type="delete">Delete</a></li>
+ <li t-if="widget.editable"><a type="edit">Edit Post</a></li>
+ <li t-if="widget.deletable"><a type="delete">Delete</a></li>
<li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
</ul>
</div>
diff --git a/addons/website_hr/views/website_hr_view.xml b/addons/website_hr/views/website_hr_view.xml
index f4592f80392..72e3f8d8ca8 100644
--- a/addons/website_hr/views/website_hr_view.xml
+++ b/addons/website_hr/views/website_hr_view.xml
@@ -7,12 +7,12 @@
<field name="model">hr.employee</field>
<field name="inherit_id" ref="hr.view_employee_form"/>
<field name="arch" type="xml">
- <xpath expr="//div[@name='button_box']" position="inside">
- <button class="oe_inline oe_stat_button" name="open_website_url"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" name="open_website_url"
type="object" icon="fa-globe">
<field name="website_published" widget="website_button"/>
</button>
- </xpath>
+ </div>
</field>
</record>
diff --git a/addons/website_hr_recruitment/views/hr_job_views.xml b/addons/website_hr_recruitment/views/hr_job_views.xml
index 6edfb88b1fd..6e426caa3a5 100644
--- a/addons/website_hr_recruitment/views/hr_job_views.xml
+++ b/addons/website_hr_recruitment/views/hr_job_views.xml
@@ -6,12 +6,12 @@
<field name="model">hr.job</field>
<field name="inherit_id" ref="hr_recruitment.hr_job_survey"/>
<field name="arch" type="xml">
- <xpath expr="//div[@class='oe_button_box']" position="inside">
- <button class="oe_inline oe_stat_button" name="open_website_url"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" name="open_website_url"
type="object" icon="fa-globe">
<field name="website_published" widget="website_button"/>
</button>
- </xpath>
+ </div>
</field>
</record>
</data>
diff --git a/addons/website_links/views/website_links.xml b/addons/website_links/views/website_links.xml
index 8ee1b694b11..8616019de41 100644
--- a/addons/website_links/views/website_links.xml
+++ b/addons/website_links/views/website_links.xml
@@ -27,7 +27,7 @@
<field name="arch" type="xml">
<form string="Website Link">
<sheet>
- <div class="oe_button_box pull-right">
+ <div class="oe_button_box" name="button_box">
<button type="object" icon="fa-sign-out" name="action_visit_page"
string="Visit Page" class="oe_stat_button"/>
diff --git a/addons/website_livechat/views/website_livechat_view.xml b/addons/website_livechat/views/website_livechat_view.xml
index 524cc7d4a49..ae1402b7b38 100644
--- a/addons/website_livechat/views/website_livechat_view.xml
+++ b/addons/website_livechat/views/website_livechat_view.xml
@@ -7,12 +7,12 @@
<field name="model">im_livechat.channel</field>
<field name="inherit_id" ref="im_livechat.im_livechat_channel_view_form"/>
<field name="arch" type="xml">
- <xpath expr="//div[@name='buttons']" position="inside">
- <button class="oe_inline oe_stat_button" name="open_website_url"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" name="open_website_url"
type="object" icon="fa-globe">
<field name="website_published" widget="website_button"/>
</button>
- </xpath>
+ </div>
</field>
</record>
diff --git a/addons/website_partner/views/res_partner_view.xml b/addons/website_partner/views/res_partner_view.xml
index 10f0dd0e9de..343733faa7c 100644
--- a/addons/website_partner/views/res_partner_view.xml
+++ b/addons/website_partner/views/res_partner_view.xml
@@ -10,15 +10,15 @@
<field eval="18" name="priority"/>
<field name="arch" type="xml">
<data>
- <xpath expr="//div[@name='buttons']" position="inside">
- <button class="oe_inline oe_stat_button" name="open_website_url"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" name="open_website_url"
type="object" icon="fa-globe">
<field name="website_published" widget="website_button"/>
</button>
- </xpath>
+ </div>
</data>
</field>
</record>
</data>
-</openerp>
+</openerp> \ No newline at end of file
diff --git a/addons/website_sale/views/views.xml b/addons/website_sale/views/views.xml
index dd401c4e8c9..9a0ac67e033 100644
--- a/addons/website_sale/views/views.xml
+++ b/addons/website_sale/views/views.xml
@@ -29,12 +29,12 @@
<field name="website_sequence"/>
</group>
</group>
- <xpath expr="//div[@name='buttons']" position="inside">
- <button class="oe_inline oe_stat_button" name="open_website_url"
+ <div name="button_box" position="inside">
+ <button class="oe_stat_button" name="open_website_url"
type="object" icon="fa-globe">
<field name="website_published" widget="website_button"/>
</button>
- </xpath>
+ </div>
</field>
</record>
diff --git a/addons/website_slides/view/website_slides_backend.xml b/addons/website_slides/view/website_slides_backend.xml
index 24aad41e2bb..680c090547d 100644
--- a/addons/website_slides/view/website_slides_backend.xml
+++ b/addons/website_slides/view/website_slides_backend.xml
@@ -40,13 +40,13 @@
<field name="arch" type="xml">
<form string="Slide">
<sheet>
- <field name="image" widget="image" class="oe_left oe_avatar" options='{"preview_image": "image_thumb"}'/>
- <div class="oe_right oe_button_box" name="buttons">
- <button class="oe_inline oe_stat_button" name="open_website_url"
+ <div class="oe_button_box" name="button_box">
+ <button class="oe_stat_button" name="open_website_url"
type="object" icon="fa-globe">
<field name="website_published" widget="website_button"/>
</button>
</div>
+ <field name="image" widget="image" class="oe_left oe_avatar" options='{"preview_image": "image_thumb"}'/>
<div class="oe_title oe_left">
<div class="oe_edit_only">
<label for="name" string="Name"/>
@@ -194,6 +194,12 @@
<field name="arch" type="xml">
<form string="Channels">
<sheet>
+ <div class="oe_button_box" name="button_box">
+ <button class="oe_stat_button" name="open_website_url"
+ type="object" icon="fa-globe">
+ <field name="website_published" widget="website_button"/>
+ </button>
+ </div>
<div class="oe_title oe_left">
<div class="oe_edit_only">
<label for="name" string="Name"/>
@@ -202,12 +208,6 @@
<field name="name" default_focus="1" placeholder="Name"/>
</h1>
</div>
- <div class="oe_right oe_button_box" name="buttons">
- <button class="oe_inline oe_stat_button" name="open_website_url"
- type="object" icon="fa-globe">
- <field name="website_published" widget="website_button"/>
- </button>
- </div>
<field name="category_ids" widget="many2many_tags" placeholder="Categories" context="{'default_channel_id': active_id}"
domain="[('channel_id','=', active_id)]"/>
<notebook colspan="4">
diff --git a/addons/website_version/views/marketing_view.xml b/addons/website_version/views/marketing_view.xml
index 78130f3dc62..b9ab949aae4 100644
--- a/addons/website_version/views/marketing_view.xml
+++ b/addons/website_version/views/marketing_view.xml
@@ -74,7 +74,7 @@
</header>
<sheet string="Exp">
<button icon="fa-line-chart" name="website_version.action_analytic" String="Statistics" action="action"
- type="action" class="oe_stat_button pull-right" />
+ type="action" class="pull-right" />
<div class="oe_title">
<field name="google_id" invisible="1"/>
<label for="name" class="oe_edit_only"/>
@@ -173,7 +173,7 @@
<form string="version Form">
<sheet string="Snap">
<group>
- <button icon="fa-pencil" name="action_publish" string="Publish" type="object" class="oe_stat_button pull-right"/>
+ <button icon="fa-pencil" name="action_publish" string="Publish" type="object" class="pull-right"/>
</group>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>