[IMP] *: M2X search/add popup should display a kanban instead of a list in mobile

- Add support of "kanban_view_ref" on many2x fields:
For many2one fields, this specific kanban view will be opened when you click
on this field. Note that in desktop, the behavior stay unchanged:
'Search More' will open the tree view.
For many2many fields, this specific kanban view will be opened when you add
a record in mobile.

- Add support "selection_mode" in kanban views.
This boolean is set to true when you want to use a kaban view to
select a record instead of open a record.
"selection_mode" is now passed in qweb_context to allow developers
to use t-if='selection_mode' in kanban views to show or hide elements;
buttons, dropdowns, anchor tags are not necessary when selection_mode
is enabled. So those elements can be hidden based on this condition.
Useful when kanban view is opened from m2o in mobile environment.

Task ID : 1924779

closes odoo/odoo#30747

Signed-off-by: Xavier Dollé (xdo) <xdo@odoo.com>
This commit is contained in:
Robot Odoo
2019-08-09 14:50:29 +02:00
committed by GitHub
42 changed files with 253 additions and 133 deletions
@@ -14,7 +14,7 @@
<field name="activity_state"/>
<templates>
<t t-name="kanban-box">
<div t-attf-class="#{kanban_color(record.color.raw_value)}">
<div t-attf-class="#{!selection_mode ? kanban_color(record.color.raw_value) : ''}">
<t t-value="JSON.parse(record.kanban_dashboard.raw_value)" t-set="dashboard"/>
<t t-value="record.type.raw_value" t-set="journal_type"/>
<t t-call="JournalTop"/>
@@ -205,14 +205,14 @@
<templates>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_card oe_kanban_global_click">
<div class="text-center">
<div t-attf-class="#{!selection_mode ? 'text-center' : ''}">
<strong><span><field name="display_name"/></span></strong>
</div>
<hr class="mt8 mb8"/>
<div class="row">
<div class="col-12 text-center">
<div t-attf-class="col-12 #{!selection_mode ? 'text-center' : ''}">
<span>
<strong>Balance: <field name="balance" widget="monetary"/></strong>
Balance: <field name="balance" widget="monetary"/>
</span>
</div>
</div>
+1 -1
View File
@@ -393,7 +393,7 @@
<progressbar field="activity_state" colors='{"planned": "success", "today": "warning", "overdue": "danger"}' sum_field="planned_revenue" help="This bar allows to filter the opportunities based on scheduled activities."/>
<templates>
<t t-name="kanban-box">
<div t-attf-class="#{kanban_color(record.color.raw_value)} oe_kanban_global_click">
<div t-attf-class="#{!selection_mode ? kanban_color(record.color.raw_value) : ''} oe_kanban_global_click">
<div class="o_dropdown_kanban dropdown">
<a class="dropdown-toggle o-no-caret btn" role="button" data-toggle="dropdown" href="#" aria-label="Dropdown menu" title="Dropdown menu">
+1 -1
View File
@@ -46,7 +46,7 @@
<group>
<field name="is_won"/>
<field name="fold"/>
<field name="team_id" options='{"no_open": True, "no_create": True}' attrs="{'invisible': [('team_count', '&lt;=', 1)]}"/>
<field name="team_id" options='{"no_open": True, "no_create": True}' attrs="{'invisible': [('team_count', '&lt;=', 1)]}" kanban_view_ref="%(sales_team.crm_team_view_kanban)s"/>
</group>
<field name="team_count" invisible="1"/>
</group>
@@ -25,7 +25,7 @@
<field name="phone"/>
<field name="stage_id"/>
<field name="user_id"/>
<field name="team_id"/>
<field name="team_id" kanban_view_ref="%(sales_team.crm_team_view_kanban)s"/>
</tree>
</field>
</group>
@@ -54,7 +54,7 @@
<field name="deduplicate" class="oe_inline"/>
</group>
<group string="Assign these opportunities to">
<field name="team_id"/>
<field name="team_id" kanban_view_ref="%(sales_team.crm_team_view_kanban)s"/>
<field name="user_ids" widget="many2many_tags" domain="[('share', '=', False)]"/>
<field name="force_assignation"/>
</group>
@@ -8,7 +8,7 @@
<form string="Merge Leads/Opportunities">
<group string="Assign opportunities to">
<field name="user_id" class="oe_inline"/>
<field name="team_id" class="oe_inline"/>
<field name="team_id" class="oe_inline" kanban_view_ref="%(sales_team.crm_team_view_kanban)s"/>
</group>
<group string="Select Leads/Opportunities">
<field name="opportunity_ids" nolabel="1">
@@ -50,7 +50,7 @@
</group>
<group name="lead_info" string="Lead Information">
<field name="lead_type" groups="crm.group_use_lead" invisible="context.get('is_modal')" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="team_id" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="team_id" attrs="{'readonly': [('state', '!=', 'draft')]}" kanban_view_ref="%(sales_team.crm_team_view_kanban)s"/>
<field name="user_id" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="tag_ids" widget="many2many_tags" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
</group>
@@ -75,7 +75,7 @@
<group>
<field name="lead_type" groups="crm.group_use_lead"/>
<field name="suffix"/>
<field name="team_id"/>
<field name="team_id" kanban_view_ref="%(sales_team.crm_team_view_kanban)s"/>
<field name="user_id"/>
</group>
<group>
+1 -1
View File
@@ -315,7 +315,7 @@
<field name="color"/>
<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 t-attf-class="{{!selection_mode ? 'oe_kanban_color_' + kanban_getcolor(record.color.raw_value) : ''}} oe_kanban_card oe_kanban_global_click">
<div class="o_dropdown_kanban dropdown">
<a class="dropdown-toggle o-no-caret btn" role="button" data-toggle="dropdown" href="#" aria-label="Dropdown menu" title="Dropdown menu">
@@ -58,6 +58,23 @@
</field>
</record>
<record id='fleet_vehicle_model_view_kanban' model='ir.ui.view'>
<field name="name">fleet.vehicle.model.kanban</field>
<field name="model">fleet.vehicle.model</field>
<field name="arch" type="xml">
<kanban string="Models">
<templates>
<t t-name="kanban-box">
<div class="oe_kanban_details">
<div><strong><field name="name"/></strong></div>
<div><field name="brand_id"/></div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<record id='fleet_vehicle_model_view_search' model='ir.ui.view'>
<field name="name">fleet.vehicle.model.search</field>
<field name="model">fleet.vehicle.model</field>
+2 -2
View File
@@ -247,7 +247,7 @@
</li>
</ul>
</div>
<div class="o_kanban_button">
<div class="o_kanban_button" t-if="!selection_mode">
<a t-if="record.contract_count.raw_value>0" data-type="object"
data-name="return_action_to_open" href="#" class="oe_kanban_action oe_kanban_action_a"
data-context='{"xml_id":"fleet_vehicle_log_contract_action"}'>
@@ -261,7 +261,7 @@
</span>
</a>
</div>
<div class="o_kanban_inline_block">
<div class="o_kanban_inline_block" t-if="!selection_mode">
<field name="activity_ids" widget="kanban_activity"/>
</div>
</div>
+1 -1
View File
@@ -138,7 +138,7 @@
</t>
</div>
</div>
<div t-if="record.remaining_sending.value != 0" class="o_kanban_button">
<div t-if="record.remaining_sending.value != 0 and !selection_mode" class="o_kanban_button">
<button type="action" name="%(action_grant_wizard)d" class="oe_highlight btn btn-primary">Grant</button>
</div>
</div>
+3 -3
View File
@@ -62,17 +62,17 @@
<field name="color"/>
<templates>
<t t-name="kanban-box">
<div t-attf-class="#{kanban_color(record.color.raw_value)}">
<div t-attf-class="#{!selection_mode ? kanban_color(record.color.raw_value) : ''}">
<div t-attf-class="o_kanban_card_header">
<div class="o_kanban_card_header_title">
<div class="o_primary"><field name="name"/></div>
<div class="o_secondary"><field name="company_id" groups="base.group_multi_company"/></div>
</div>
<div class="o_kanban_manage_button_section">
<div class="o_kanban_manage_button_section" t-if="!selection_mode">
<a class="o_kanban_manage_toggle_button" href="#"><i class="fa fa-ellipsis-v" role="img" aria-label="Manage" title="Manage"/></a>
</div>
</div>
<div class="container o_kanban_card_content">
<div class="container o_kanban_card_content" t-if="!selection_mode">
<div class="row">
<div class="col-6 o_kanban_primary_left">
<button class="btn btn-primary" name="%(act_employee_from_department)d" type="action">Employees</button>
+1 -1
View File
@@ -69,7 +69,7 @@
<div>
<span><field name="department_id"/>&amp;nbsp;</span>
</div>
<div>
<div t-if="!selection_mode">
<span>Vacancies : <field name="expected_employees"/></span>
<span t-att-class="record.state.raw_value == 'recruit' and 'float-right badge badge-success' or 'float-right badge badge-danger'">
<field name="state"/>
@@ -241,7 +241,7 @@
<templates>
<t t-name="kanban-box">
<div class="oe_kanban_card oe_kanban_global_click">
<div class="o_dropdown_kanban dropdown" groups="base.group_user">
<div class="o_dropdown_kanban dropdown" t-if="!selection_mode" groups="base.group_user">
<a class="dropdown-toggle o-no-caret btn" role="button" data-toggle="dropdown" href="#" aria-label="Dropdown menu" title="Dropdown menu">
<span class="fa fa-ellipsis-v"/>
</a>
+1 -1
View File
@@ -26,7 +26,7 @@
<field name="user_id"/>
<templates>
<t t-name="kanban-box">
<div t-attf-class="#{kanban_color(record.color.raw_value)}">
<div t-attf-class="#{!selection_mode ? kanban_color(record.color.raw_value) : ''}">
<div t-attf-class="o_kanban_card_header">
<div class="o_kanban_card_header_title">
<div class="o_primary col-12"><t t-esc="record.name.value"/></div>
@@ -289,7 +289,7 @@
<progressbar field="activity_state" colors='{"planned": "success", "overdue": "danger", "today": "warning"}'/>
<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 oe_applicant_kanban oe_semantic_html_override">
<div t-attf-class="{{!selection_mode ? 'oe_kanban_color_' + kanban_getcolor(record.color.raw_value) : ''}} oe_kanban_card oe_kanban_global_click oe_applicant_kanban oe_semantic_html_override">
<div class="o_dropdown_kanban dropdown">
<a class="dropdown-toggle o-no-caret btn" role="button" data-toggle="dropdown" href="#" aria-label="Dropdown menu" title="Dropdown menu">
<span class="fa fa-ellipsis-v"/>
@@ -148,8 +148,8 @@
<field name="color"/>
<templates>
<t t-name="kanban-box">
<div t-attf-class="#{kanban_color(record.color.raw_value)} oe_kanban_global_click">
<div class="o_dropdown_kanban dropdown">
<div t-attf-class="#{!selection_mode ? kanban_color(record.color.raw_value) : ''} oe_kanban_global_click">
<div class="o_dropdown_kanban dropdown" t-if="!selection_mode">
<a class="dropdown-toggle o-no-caret btn" role="button" data-toggle="dropdown" href="#" aria-label="Dropdown menu" title="Dropdown menu">
<span class="fa fa-bars fa-lg"/>
</a>
@@ -131,7 +131,7 @@
</ul>
</t>
<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 oe_semantic_html_override">
<div t-attf-class="{{!selection_mode ? 'oe_kanban_color_' + kanban_getcolor(record.color.raw_value) : ''}} oe_kanban_card oe_kanban_global_click oe_semantic_html_override">
<div class="o_dropdown_kanban dropdown">
<a role="button" class="dropdown-toggle o-no-caret btn" data-toggle="dropdown" href="#" aria-label="Dropdown menu" title="Dropdown menu">
@@ -432,8 +432,8 @@
</ul>
</t>
<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="o_dropdown_kanban dropdown">
<div t-attf-class="{{!selection_mode ? 'oe_kanban_color_' + kanban_getcolor(record.color.raw_value) : ''}} oe_kanban_card oe_kanban_global_click">
<div class="o_dropdown_kanban dropdown" t-if="!selection_mode">
<a role="button" class="dropdown-toggle o-no-caret btn" data-toggle="dropdown" href="#" aria-label="Dropdown menu" title="Dropdown menu">
<span class="fa fa-ellipsis-v"/>
@@ -455,15 +455,15 @@
</div>
<div class="o_kanban_record_bottom">
<div class="oe_kanban_bottom_left">
<div class="badge badge-danger" t-if="record.maintenance_open_count.raw_value" >
<div class="badge badge-danger" t-if="!selection_mode and record.maintenance_open_count.raw_value" >
<t t-raw="record.maintenance_open_count.raw_value"/> Request
</div>
<div class="badge badge-secondary" t-if="record.next_action_date.raw_value" >
<div class="badge badge-secondary" t-if="!selection_mode and record.next_action_date.raw_value" >
<t t-raw="moment(record.next_action_date.raw_value).format('MMMM Do')"/>
</div>
</div>
<div class="oe_kanban_bottom_right">
<div class="o_kanban_inline_block">
<div class="o_kanban_inline_block" t-if="!selection_mode">
<field name="activity_ids" widget="kanban_activity" />
</div>
<img t-att-src="kanban_image('res.users', 'image_64', record.owner_user_id.raw_value)" t-att-title="record.owner_user_id.value" t-att-alt="record.owner_user_id.value" width="27" height="27" class="oe_kanban_avatar"/>
@@ -819,7 +819,7 @@
<field name="todo_request_count_unscheduled"/>
<templates>
<t t-name="kanban-box">
<div t-attf-class="#{kanban_color(record.color.raw_value)}">
<div t-attf-class="#{!selection_mode ? kanban_color(record.color.raw_value) : ''}">
<div t-attf-class="o_kanban_card_header">
<div class="o_kanban_card_header_title">
<div class="o_primary">
@@ -236,8 +236,8 @@
<field name='active'/>
<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 oe_kanban_mass_mailing">
<div class="o_dropdown_kanban dropdown">
<div t-attf-class="{{!selection_mode ? 'oe_kanban_color_' + kanban_getcolor(record.color.raw_value) : ''}} oe_kanban_card oe_kanban_global_click oe_kanban_mass_mailing">
<div class="o_dropdown_kanban dropdown" t-if="!selection_mode">
<a role="button" class="dropdown-toggle o-no-caret btn" data-toggle="dropdown" href="#" aria-label="Dropdown menu" title="Dropdown menu">
<span class="fa fa-ellipsis-v"/>
</a>
@@ -262,7 +262,7 @@
</div>
</div>
</div>
<div class="o_kanban_record_body" attrs="{'invisible': [('sent_date', '=', False)]}">
<div class="o_kanban_record_body" t-if="!selection_mode" attrs="{'invisible': [('sent_date', '=', False)]}">
<t t-if="record.sent_date">
<div class="row">
<div class="col-8">
+1 -1
View File
@@ -150,7 +150,7 @@
<field name="oee_target"/>
<templates>
<t t-name="kanban-box">
<div style="width: 400px;" t-attf-class="#{kanban_color(record.color.raw_value)}">
<div style="width: 400px;" t-attf-class="#{!selection_mode ? kanban_color(record.color.raw_value) : ''}">
<div t-attf-class="o_kanban_card_header o_kanban_record_top">
<div class="o_kanban_record_headings o_kanban_card_header_title">
<span class="o_primary ml8" style="display: inline-block">
+5 -4
View File
@@ -12,20 +12,21 @@
</field>
<xpath expr='//div[@name="stock_picking"]' position="after">
<div t-if="record.code.raw_value == 'mrp_operation'" t-attf-class="#{kanban_color(record.color.raw_value)}">
<div t-if="record.code.raw_value == 'mrp_operation'" t-attf-class="#{!selection_mode ? kanban_color(record.color.raw_value) : ''}">
<div>
<div t-attf-class="o_kanban_card_header">
<div class="o_kanban_card_header_title">
<a type="object" name="get_mrp_stock_picking_action_picking_type" class="o_primary">
<a type="object" name="get_mrp_stock_picking_action_picking_type" class="o_primary" t-if="!selection_mode">
<field name="name"/>
</a>
<span class="o_primary" t-if="selection_mode"><field name="name"/></span>
<div class="o_secondary"><field class="o_secondary" name="warehouse_id"/></div>
</div>
<div class="o_kanban_manage_button_section">
<div class="o_kanban_manage_button_section" t-if="!selection_mode">
<a class="o_kanban_manage_toggle_button" href="#"><i class="fa fa-ellipsis-v" role="img" aria-label="Manage" title="Manage"/></a>
</div>
</div>
<div class="container o_kanban_card_content">
<div class="container o_kanban_card_content" t-if="!selection_mode">
<div class="row">
<div class="col-6 o_kanban_primary_left">
<button class="btn btn-primary" name="%(mrp_production_action_picking_deshboard)d" type="action" context="{'search_default_todo': 1}">
+1 -1
View File
@@ -92,7 +92,7 @@
<templates>
<t t-name="kanban-box">
<div t-attf-class="#{kanban_color(record.color.raw_value)} oe_kanban_global_click_edit oe_semantic_html_override oe_kanban_card">
<div t-attf-class="#{!selection_mode ? kanban_color(record.color.raw_value) : ''} oe_kanban_global_click_edit oe_semantic_html_override oe_kanban_card">
<field name="tag_ids" widget="many2many_tags" options="{'color_field': 'color'}"/>
+3 -3
View File
@@ -167,9 +167,9 @@
<t t-if="installed">
<field name="environment" widget="label_selection" options="{'classes': {'test': 'warning', 'production': 'success'}}"/>
</t>
<button t-if="!installed" type="object" class="btn btn-secondary float-right" name="button_immediate_install">Install</button>
<button t-if="installed and !record.website_published.raw_value" type="edit" class="btn btn-primary float-right">Activate</button>
<button t-if="installed and record.website_published.raw_value" type="edit" class="btn btn-primary float-right">Configure</button>
<button t-if="!installed and !selection_mode" type="object" class="btn btn-secondary float-right" name="button_immediate_install">Install</button>
<button t-if="installed and !record.website_published.raw_value and !selection_mode" type="edit" class="btn btn-primary float-right">Activate</button>
<button t-if="installed and record.website_published.raw_value and !selection_mode" type="edit" class="btn btn-primary float-right">Configure</button>
</div>
</div>
</t>
+1 -1
View File
@@ -15,7 +15,7 @@
<div class="text-muted">
Sales are reported to the following sales team
</div>
<field name="crm_team_id" domain="['|', ('company_id', '=', company_id), ('company_id', '=', False)]"/>
<field name="crm_team_id" kanban_view_ref="%(sales_team.crm_team_view_kanban)s" domain="['|', ('company_id', '=', company_id), ('company_id', '=', False)]"/>
</div>
</div>
</div>
+2 -2
View File
@@ -6,7 +6,7 @@
<field name="inherit_id" ref="point_of_sale.view_pos_session_search"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='config_id']" position="after">
<field name="crm_team_id"/>
<field name="crm_team_id" kanban_view_ref="%(sales_team.crm_team_view_kanban)s"/>
</xpath>
</field>
</record>
@@ -25,7 +25,7 @@
<field name="inherit_id" ref="point_of_sale.view_pos_config_search"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='name']" position="after">
<field name="crm_team_id"/>
<field name="crm_team_id" kanban_view_ref="%(sales_team.crm_team_view_kanban)s"/>
</xpath>
</field>
</record>
+4 -4
View File
@@ -560,7 +560,7 @@
<progressbar field="kanban_state" colors='{"done": "success", "blocked": "danger"}'/>
<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 t-attf-class="{{!selection_mode ? 'oe_kanban_color_' + kanban_getcolor(record.color.raw_value) : ''}} oe_kanban_card oe_kanban_global_click">
<div class="oe_kanban_content">
<div class="o_kanban_record_top">
<div class="o_kanban_record_headings">
@@ -573,7 +573,7 @@
<t t-else="record.email_from.raw_value"><span><field name="email_from"/></span></t>
</small>
</div>
<div class="o_dropdown_kanban dropdown" groups="base.group_user">
<div class="o_dropdown_kanban dropdown" t-if="!selection_mode" groups="base.group_user">
<a role="button" class="dropdown-toggle o-no-caret btn" data-toggle="dropdown" href="#" aria-label="Dropdown menu" title="Dropdown menu">
<span class="fa fa-ellipsis-v"/>
</a>
@@ -593,7 +593,7 @@
<field name="displayed_image_id" widget="attachment_image"/>
</div>
</div>
<div class="o_kanban_record_bottom">
<div class="o_kanban_record_bottom" t-if="!selection_mode">
<div class="oe_kanban_bottom_left">
<field name="priority" widget="priority"/>
<field name="activity_ids" widget="kanban_activity"/>
@@ -606,7 +606,7 @@
<span style="font-weight:bold;" class="fa fa-fw mt4 fa-frown-o text-danger" t-if="record.rating_last_value.value == 1" title="Latest Rating: Higly Dissatisfied" role="img" aria-label="Sad face"/>
</b>
</div>
<div class="oe_kanban_bottom_right">
<div class="oe_kanban_bottom_right" t-if="!selection_mode">
<field name="kanban_state" widget="state_selection" groups="base.group_user"/>
<img t-att-src="kanban_image('res.users', 'image_64', record.user_id.raw_value)" t-att-title="record.user_id.value" t-att-alt="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
</div>
+2 -2
View File
@@ -608,7 +608,7 @@
<group name="sales_person" string="Sales">
<field name="date_order" attrs="{'invisible': [('state', 'in', ['sale', 'done', 'cancel'])]}" string="Quotation Date" groups="base.group_no_one"/>
<field name="user_id"/>
<field name="team_id" options="{'no_create': True}"/>
<field name="team_id" kanban_view_ref="%(sales_team.crm_team_view_kanban)s" options="{'no_create': True}"/>
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
<field name="require_signature" groups="base.group_no_one"/>
<field name="require_payment" groups="base.group_no_one"/>
@@ -1135,7 +1135,7 @@
<attribute name="groups">product.group_discount_per_so_line</attribute>
</xpath>
<xpath expr="//group[@name='sale_info_group']" position="inside">
<field name="team_id"/>
<field name="team_id" kanban_view_ref="%(sales_team.crm_team_view_kanban)s"/>
</xpath>
<xpath expr="//group[@id='other_tab_group']" position="inside">
<group string="Marketing"
@@ -13,7 +13,7 @@
<field name="is_favorite"/>
<templates>
<t t-name="kanban-box">
<div t-attf-class="#{kanban_color(record.color.raw_value)}">
<div t-attf-class="#{!selection_mode ? kanban_color(record.color.raw_value) : ''}">
<div t-attf-class="o_kanban_card_header">
<div class="o_kanban_card_header_title">
<div class="o_primary"><field name="name"/></div>
+7 -4
View File
@@ -562,22 +562,25 @@ action = action_values
<field name="count_picking_backorders"/>
<templates>
<t t-name="kanban-box">
<div t-if="['incoming', 'outgoing', 'internal'].indexOf(record.code.raw_value) > -1" t-attf-class="#{kanban_color(record.color.raw_value)}" name="stock_picking">
<div t-if="['incoming', 'outgoing', 'internal'].indexOf(record.code.raw_value) > -1" t-attf-class="#{!selection_mode ? kanban_color(record.color.raw_value) : ''}" name="stock_picking">
<div>
<div t-attf-class="o_kanban_card_header">
<div class="o_kanban_card_header_title">
<div class="o_primary">
<div class="o_primary" t-if="!selection_mode">
<a type="object" name="get_stock_picking_action_picking_type">
<field name="name"/>
</a>
</div>
<div class="o_primary" t-if="selection_mode">
<field name="name"/>
</div>
<div class="o_secondary"><field class="o_secondary" name="warehouse_id"/></div>
</div>
<div class="o_kanban_manage_button_section">
<div class="o_kanban_manage_button_section" t-if="!selection_mode">
<a class="o_kanban_manage_toggle_button" href="#"><i class="fa fa-ellipsis-v" role="img" aria-label="Manage" title="Manage"/></a>
</div>
</div>
<div class="container o_kanban_card_content">
<div class="container o_kanban_card_content" t-if="!selection_mode">
<div class="row">
<div class="col-6 o_kanban_primary_left">
<button class="btn btn-primary" name="get_action_picking_tree_ready" type="object">
+4 -4
View File
@@ -156,8 +156,8 @@
<field name="activity_ids" />
<field name="activity_state" />
<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 o_kanban_card_survey">
<div class="o_dropdown_kanban dropdown" t-if="widget.editable">
<div t-name="kanban-box" t-attf-class="{{!selection_mode ? 'oe_kanban_color_' + kanban_getcolor(record.color.raw_value) : ''}} oe_kanban_card oe_kanban_global_click o_kanban_card_survey">
<div class="o_dropdown_kanban dropdown" t-if="widget.editable and !selection_mode">
<a role="button" class="dropdown-toggle o-no-caret btn" data-toggle="dropdown" href="#" aria-label="Dropdown menu" title="Dropdown menu">
<span class="fa fa-ellipsis-v"/>
@@ -176,7 +176,7 @@
</div>
<div class="col-2"><i t-if="record.certificate.raw_value === true" title="Certification" class="certification_icon fa fa-trophy"></i></div>
</div>
<div class="o_kanban_record_bottom">
<div class="o_kanban_record_bottom" t-if="!selection_mode">
<ul class="list-unstyled">
<li>
<a type="object" name="action_test_survey">Test</a>
@@ -190,7 +190,7 @@
</li>
</ul>
</div>
<div class="o_kanban_record_bottom">
<div class="o_kanban_record_bottom" t-if="!selection_mode">
<div class="oe_kanban_bottom_left"/>
<div class="oe_kanban_bottom_right">
<field name="activity_ids" widget="kanban_activity" />
@@ -393,6 +393,7 @@ var FieldMany2One = AbstractField.extend({
initial_view: view,
disable_multiple_selection: true,
no_create: !self.can_create,
kanban_view_ref: this.attrs.kanban_view_ref,
on_selected: function (records) {
self.reinitialize(records[0]);
self.activate();
@@ -1750,6 +1751,7 @@ var FieldMany2Many = FieldX2Many.extend({
title: _t("Add: ") + this.string,
no_create: this.nodeOptions.no_create || !this.activeActions.create,
fields_view: this.attrs.views.form,
kanban_view_ref: this.attrs.kanban_view_ref,
on_selected: function (records) {
var resIDs = _.pluck(records, 'id');
var newIDs = _.difference(resIDs, self.value.res_ids);
@@ -52,6 +52,7 @@ var KanbanRecord = Widget.extend({
this.editable = options.editable;
this.deletable = options.deletable;
this.read_only_mode = options.read_only_mode;
this.selectionMode = options.selectionMode;
this.qweb = options.qweb;
this.subWidgets = {};
@@ -345,6 +346,10 @@ var KanbanRecord = Widget.extend({
this.$el.addClass('o_kanban_record').attr("tabindex", 0);
this.$el.attr('role', 'article');
this.$el.data('record', this);
// forcefully add class oe_kanban_global_click to have clickable record always to select it
if (this.selectionMode) {
this.$el.addClass('oe_kanban_global_click');
}
if (this.$el.hasClass('oe_kanban_global_click') ||
this.$el.hasClass('oe_kanban_global_click_edit')) {
this.$el.on('click', this._onGlobalClick.bind(this));
@@ -502,6 +507,7 @@ var KanbanRecord = Widget.extend({
kanban_getcolor: this._getColorID.bind(this),
kanban_getcolorname: this._getColorname.bind(this),
kanban_compute_domain: this._computeDomain.bind(this),
selection_mode: this.selectionMode,
read_only_mode: this.read_only_mode,
record: this.record,
user_context: this.getSession().user_context,
@@ -36,6 +36,7 @@ var KanbanView = BasicView.extend({
// false so that they will won't be loaded by the initial load
this.loadParams.openGroupByDefault = config.device.isMobile ? false : true;
this.loadParams.type = 'list';
this.noDefaultGroupby = params.noDefaultGroupby;
var progressBar;
utils.traverse(this.arch, function (n) {
var isProgressBar = (n.tag === 'progressbar');
@@ -70,6 +71,7 @@ var KanbanView = BasicView.extend({
editable: activeActions.edit,
deletable: activeActions.delete,
read_only_mode: params.readOnlyMode,
selectionMode: params.selectionMode,
};
this.rendererParams.quickCreateEnabled = this._isQuickCreateEnabled();
this.rendererParams.readOnlyMode = params.readOnlyMode;
@@ -79,7 +81,7 @@ var KanbanView = BasicView.extend({
}
this.controllerParams.on_create = archAttrs.on_create;
this.controllerParams.hasButtons = true;
this.controllerParams.hasButtons = !params.selectionMode ? true : false;
this.controllerParams.quickCreateEnabled = this.rendererParams.quickCreateEnabled;
@@ -114,10 +116,12 @@ var KanbanView = BasicView.extend({
*/
_updateMVCParams: function () {
this._super.apply(this, arguments);
var defaultGroupBy = this.arch.attrs.default_group_by;
this.loadParams.groupBy = defaultGroupBy ?
[defaultGroupBy] :
(this.loadParams.groupedBy || []);
if (!this.noDefaultGroupby) {
var defaultGroupBy = this.arch.attrs.default_group_by;
this.loadParams.groupBy = defaultGroupBy ?
[defaultGroupBy] :
(this.loadParams.groupedBy || []);
}
},
});
@@ -0,0 +1,60 @@
odoo.define('web.select_create_controllers_registry', function (require) {
"use strict";
return {};
});
odoo.define('web._select_create_controllers_registry', function (require) {
"use strict";
var KanbanController = require('web.KanbanController');
var ListController = require('web.ListController');
var select_create_controllers_registry = require('web.select_create_controllers_registry');
var SelectCreateKanbanController = KanbanController.extend({
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* Override to select the clicked record instead of opening it
*
* @override
* @private
*/
_onOpenRecord: function (ev) {
var selectedRecord = this.model.get(ev.data.id);
this.trigger_up('select_record', {
id: selectedRecord.res_id,
display_name: selectedRecord.data.display_name,
});
},
});
var SelectCreateListController = ListController.extend({
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* Override to select the clicked record instead of opening it
*
* @override
* @private
*/
_onOpenRecord: function (ev) {
var selectedRecord = this.model.get(ev.data.id);
this.trigger_up('select_record', {
id: selectedRecord.res_id,
display_name: selectedRecord.data.display_name,
});
},
});
_.extend(select_create_controllers_registry, {
SelectCreateListController: SelectCreateListController,
SelectCreateKanbanController: SelectCreateKanbanController,
});
});
+69 -62
View File
@@ -5,9 +5,8 @@ var config = require('web.config');
var core = require('web.core');
var Dialog = require('web.Dialog');
var dom = require('web.dom');
var ListController = require('web.ListController');
var ListView = require('web.ListView');
var view_registry = require('web.view_registry');
var select_create_controllers_registry = require('web.select_create_controllers_registry');
var _t = core._t;
@@ -279,26 +278,6 @@ var FormViewDialog = ViewDialog.extend({
},
});
var SelectCreateListController = ListController.extend({
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* Override to select the clicked record instead of opening it
*
* @override
* @private
*/
_onOpenRecord: function (ev) {
var selectedRecord = this.model.get(ev.data.id);
this.trigger_up('select_record', {
id: selectedRecord.res_id,
display_name: selectedRecord.data.display_name,
});
},
});
/**
* Search dialog (displays a list of records and permits to create a new one by switching to a form view)
*/
@@ -330,6 +309,7 @@ var SelectCreateDialog = ViewDialog.extend({
_.defaults(this.options, { initial_view: 'search' });
this.on_selected = this.options.on_selected || (function () {});
this.initialIDs = this.options.initial_ids;
this.viewType = 'list';
},
open: function () {
@@ -338,12 +318,14 @@ var SelectCreateDialog = ViewDialog.extend({
}
var self = this;
var _super = this._super.bind(this);
return this.loadViews(this.res_model, this.context, [[false, 'list'], [false, 'search']], {})
var viewRefID = this.viewType === 'kanban' ?
(this.options.kanban_view_ref && JSON.parse(this.options.kanban_view_ref) || false) : false;
return this.loadViews(this.res_model, this.context, [[viewRefID, this.viewType], [false, 'search']], {})
.then(this.setup.bind(this))
.then(function (fragment) {
self.opened().then(function () {
dom.append(self.$el, fragment, {
callbacks: [{widget: self.listController}],
callbacks: [{widget: self.viewController}],
in_DOM: true,
});
self.set_buttons(self.__buttons);
@@ -360,55 +342,43 @@ var SelectCreateDialog = ViewDialog.extend({
if (this.initialIDs) {
domain = domain.concat([['id', 'in', this.initialIDs]]);
}
var listView = new ListView(fieldsViews.list, _.extend({
var ViewClass = view_registry.get(this.viewType);
var viewOptions = {};
var selectCreateController;
if (this.viewType === 'list') { // add listview specific options
_.extend(viewOptions, {
hasSelectors: !this.options.disable_multiple_selection,
readonly: true,
}, this.options.list_view_options);
selectCreateController = select_create_controllers_registry.SelectCreateListController;
}
if (this.viewType === 'kanban') {
_.extend(viewOptions, {
noDefaultGroupby: true,
selectionMode: this.options.selectionMode || false,
});
selectCreateController = select_create_controllers_registry.SelectCreateKanbanController;
}
var view = new ViewClass(fieldsViews[this.viewType], _.extend(viewOptions, {
action: {
controlPanelFieldsView: fieldsViews.search,
help: _.str.sprintf("<p>%s</p>", _t("No records found!")),
},
action_buttons: false,
dynamicFilters: this.options.dynamicFilters,
context: this.context,
domain: domain,
hasSelectors: !this.options.disable_multiple_selection,
modelName: this.res_model,
readonly: true,
withBreadcrumbs: false,
withSearchPanel: false,
}, this.options.list_view_options));
listView.setController(SelectCreateListController);
return listView.getController(this).then(function (controller) {
self.listController = controller;
}));
view.setController(selectCreateController);
return view.getController(this).then(function (controller) {
self.viewController = controller;
// render the footer buttons
self.__buttons = [{
text: _t("Cancel"),
classes: 'btn-secondary o_form_button_cancel',
close: true,
}];
if (!self.options.no_create) {
self.__buttons.unshift({
text: _t("Create"),
classes: 'btn-primary',
click: self.create_edit_record.bind(self)
});
}
if (!self.options.disable_multiple_selection) {
self.__buttons.unshift({
text: _t("Select"),
classes: 'btn-primary o_select_button',
disabled: true,
close: true,
click: function () {
var records = self.listController.getSelectedRecords();
var values = _.map(records, function (record) {
return {
id: record.res_id,
display_name: record.data.display_name,
};
});
self.on_selected(values);
},
});
}
return self.listController.appendTo(fragment);
self._prepareButtons();
return self.viewController.appendTo(fragment);
}).then(function () {
return fragment;
});
@@ -439,6 +409,43 @@ var SelectCreateDialog = ViewDialog.extend({
});
return isFocusSet;
},
/**
* prepare buttons for dialog footer based on options
*
* @private
*/
_prepareButtons: function () {
this.__buttons = [{
text: _t("Cancel"),
classes: 'btn-secondary o_form_button_cancel',
close: true,
}];
if (!this.options.no_create) {
this.__buttons.unshift({
text: _t("Create"),
classes: 'btn-primary',
click: this.create_edit_record.bind(this)
});
}
if (!this.options.disable_multiple_selection) {
this.__buttons.unshift({
text: _t("Select"),
classes: 'btn-primary o_select_button',
disabled: true,
close: true,
click: function () {
var records = this.viewController.getSelectedRecords();
var values = _.map(records, function (record) {
return {
id: record.res_id,
display_name: record.data.display_name,
};
});
this.on_selected(values);
},
});
}
},
});
return {
+1
View File
@@ -320,6 +320,7 @@
<script type="text/javascript" src="/web/static/src/js/views/control_panel/search/search_filters_registry.js"></script>
<script type="text/javascript" src="/web/static/src/js/views/search_panel.js"></script>
<script type="text/javascript" src="/web/static/src/js/views/field_manager_mixin.js"></script>
<script type="text/javascript" src="/web/static/src/js/views/select_create_controllers_registry.js"></script>
<script type="text/javascript" src="/web/static/src/js/views/standalone_field_manager_mixin.js"></script>
<script type="text/javascript" src="/web/static/src/js/views/view_registry.js"></script>
<script type="text/javascript" src="/web/static/src/js/views/view_dialogs.js"></script>
@@ -16,7 +16,7 @@
<field name="activity_state"/>
<progressbar field="kanban_state" colors='{"done": "success", "blocked": "danger"}'/>
<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 t-attf-class="{{!selection_mode ? 'oe_kanban_color_' + kanban_getcolor(record.color.raw_value) : ''}} oe_kanban_card oe_kanban_global_click">
<div class="o_dropdown_kanban dropdown" groups="base.group_user">
<a role="button" class="dropdown-toggle o-no-caret btn" data-toggle="dropdown" href="#" aria-label="Dropdown menu" title="Dropdown menu">
@@ -299,7 +299,7 @@
<div class="content-group">
<div class="row mt16">
<label class="o_light_label col-lg-3" string="Sales Team" for="salesteam_id"/>
<field name="salesteam_id" />
<field name="salesteam_id" kanban_view_ref="%(sales_team.crm_team_view_kanban)s" />
</div>
<div class="row">
<label class="o_light_label col-lg-3" for="salesperson_id"/>
+8
View File
@@ -567,6 +567,9 @@ system. Available semantic components are:
``password``
indicates that a :class:`~odoo.fields.Char` field stores a password and
that its data shouldn't be displayed
``kanban_view_ref``
for opening specific kanban view when selecting records from m2o/m2m in mobile
environment
.. todo:: classes for forms
@@ -1106,6 +1109,11 @@ Possible children of the view element are:
self-explanatory
``read_only_mode``
self-explanatory
``selection_mode``
set to true when kanban view is opened in mobile environment from m2o/m2m field
for selecting records.
.. note:: clicking on m2o/m2m field in mobile environment opens kanban view
.. rubric:: buttons and fields
+1
View File
@@ -264,6 +264,7 @@
<rng:optional><rng:attribute name="write_field" /></rng:optional>
<rng:optional><rng:attribute name="text" /></rng:optional>
<rng:optional><rng:attribute name="optional" /></rng:optional>
<rng:optional><rng:attribute name="kanban_view_ref" /></rng:optional>
<rng:optional>
<rng:attribute name="force_save">
<rng:choice>
+13 -3
View File
@@ -70,24 +70,34 @@
<templates>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_global_click">
<div class="text-center">
<div t-attf-class="#{!selection_mode ? 'text-center' : ''}">
<i class="fa fa-building" role="img" aria-label="Enterprise" title="Enterprise"></i> <strong><field name="name"/></strong>
</div>
<hr class="mt4 mb4"/>
<div class="row">
<div class="row" t-if="!selection_mode">
<div t-if="record.email.value" class="col-6 text-center">
<strong>Email:</strong>
</div>
<div t-if="record.phone.value" class="col-6 text-center">
<strong>Phone</strong>
</div>
<div t-if="record.phone.value" class="col-6 text-center">
<div t-if="record.email.value" class="col-6 text-center">
<field name="email"/>
</div>
<div t-if="record.phone.value" class="col-6 text-center">
<field name="phone"/>
</div>
</div>
<div t-else="">
<div t-if="record.email.value">
<strong>Email:</strong>
<field name="email"/>
</div>
<div t-if="record.phone.value">
<strong>Phone:</strong>
<field name="phone"/>
</div>
</div>
</div>
</t>
</templates>