Description of the issue/feature this PR addresses: It is currently quite difficult to differentiate users. Most of the time, people don't take the time to upload an actual avatar so everybody looks the same. This PR generates a custom avatar with the users initials and random color to differentiate them. For res.users, res.partner and hr.employee, image fields now hold the binary image and avatar are used to show the image or svg. Current behavior before PR: Avatar had only random colors and was being saved in database, being inefficient Desired behavior after PR is merged: A new mixin defines image fields and in case no image is set, it generates an SVG image with the user's initials and random color. closes odoo/odoo#69819 Task: 2404630 Related: odoo/enterprise#18199 Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
360 lines
19 KiB
XML
360 lines
19 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<odoo><data>
|
|
<!--page history-->
|
|
<record id="website_visitor_page_view_tree" model="ir.ui.view">
|
|
<field name="name">website.track.view.tree</field>
|
|
<field name="model">website.track</field>
|
|
<field name="arch" type="xml">
|
|
<tree string="Visitor Page Views History" create="0">
|
|
<field name="visitor_id"/>
|
|
<field name="page_id"/>
|
|
<field name="url"/>
|
|
<field name="visit_datetime"/>
|
|
</tree>
|
|
</field>
|
|
</record>
|
|
|
|
<record id="website_visitor_page_view_graph" model="ir.ui.view">
|
|
<field name="name">website.track.view.graph</field>
|
|
<field name="model">website.track</field>
|
|
<field name="arch" type="xml">
|
|
<graph string="Visitor Page Views" sample="1">
|
|
<field name="url"/>
|
|
</graph>
|
|
</field>
|
|
</record>
|
|
|
|
<record id="website_visitor_page_view_search" model="ir.ui.view">
|
|
<field name="name">website.track.view.search</field>
|
|
<field name="model">website.track</field>
|
|
<field name="arch" type="xml">
|
|
<search string="Search Visitor">
|
|
<field name="visitor_id"/>
|
|
<field name="page_id"/>
|
|
<field name="url"/>
|
|
<field name="visit_datetime"/>
|
|
<filter string="Pages" name="type_page" domain="[('page_id', '!=', False)]"/>
|
|
<filter string="Urls & Pages" name="type_url" domain="[('url', '!=', False)]"/>
|
|
<group string="Group By">
|
|
<filter string="Visitor" name="group_by_visitor" domain="[]" context="{'group_by': 'visitor_id'}"/>
|
|
<filter string="Page" name="group_by_page" domain="[]" context="{'group_by': 'page_id'}"/>
|
|
<filter string="Url" name="group_by_url" domain="[]" context="{'group_by': 'url'}"/>
|
|
<filter string="Date" name="group_by_date" domain="[]" context="{'group_by': 'visit_datetime'}"/>
|
|
</group>
|
|
</search>
|
|
</field>
|
|
</record>
|
|
|
|
<record id="website_visitor_page_action" model="ir.actions.act_window">
|
|
<field name="name">Page Views History</field>
|
|
<field name="res_model">website.track</field>
|
|
<field name="view_mode">tree</field>
|
|
<field name="view_ids" eval="[(5, 0, 0),
|
|
(0, 0, {'view_mode': 'tree', 'view_id': ref('website_visitor_page_view_tree')}),
|
|
(0, 0, {'view_mode': 'graph', 'view_id': ref('website_visitor_page_view_graph')}),
|
|
]"/>
|
|
<field name="domain">[('visitor_id', '=', active_id), ('url', '!=', False)]</field>
|
|
<field name="help" type="html">
|
|
<p class="o_view_nocontent_empty_folder">
|
|
No page views yet for this visitor
|
|
</p>
|
|
</field>
|
|
</record>
|
|
|
|
<!--Website visitor actions-->
|
|
<record id="website.visitor_partner_action" model="ir.actions.act_window">
|
|
<field name="name">Partners</field>
|
|
<field name="res_model">res.partner</field>
|
|
<field name="view_mode">tree,form</field>
|
|
<field name="domain">[('visitor_ids', 'in', [active_id])]</field>
|
|
<field name="help" type="html">
|
|
<p class="o_view_nocontent_empty_folder">
|
|
No partner linked for this visitor
|
|
</p>
|
|
</field>
|
|
</record>
|
|
|
|
<!-- website visitor views -->
|
|
<record id="website_visitor_view_kanban" model="ir.ui.view">
|
|
<field name="name">website.visitor.view.kanban</field>
|
|
<field name="model">website.visitor</field>
|
|
<field name="arch" type="xml">
|
|
<kanban class="o_wvisitor_kanban" sample="1">
|
|
<field name="id"/>
|
|
<field name="country_id"/>
|
|
<field name="country_flag"/>
|
|
<field name="email"/>
|
|
<field name="is_connected"/>
|
|
<field name="display_name"/>
|
|
<field name="last_visited_page_id"/>
|
|
<field name="page_ids"/>
|
|
<field name="partner_id"/>
|
|
<field name="partner_image"/>
|
|
<templates>
|
|
<t t-name="kanban-box">
|
|
<div class="oe_kanban_global_click o_wvisitor_kanban_card">
|
|
<!-- displayed in ungrouped mode -->
|
|
<div class="o_kanban_detail_ungrouped row mx-0">
|
|
<div class="o_wvisitor_kanban_image">
|
|
<img t-if="record.partner_image.raw_value"
|
|
t-att-src="kanban_image('res.partner', 'avatar_128', record.partner_id.raw_value)"
|
|
width="54px" height="54px" alt="Visitor"/>
|
|
<img t-else=""
|
|
t-attf-src="/base/static/img/avatar_grey.png"
|
|
width="54px" height="54px" alt="Visitor"/>
|
|
</div>
|
|
<div class="col o_wvisitor_name mr-2">
|
|
<div>
|
|
<b><field name="display_name"/></b>
|
|
<div class="float-right">
|
|
<span class="fa fa-circle text-success" t-if="record.is_connected.raw_value" aria-label="Online" title="Online"/>
|
|
<span class="fa fa-circle text-danger" t-else="" aria-label="Offline" title="Offline"/>
|
|
</div>
|
|
<!-- Double check is necessary for sample view (or error image are shown) -->
|
|
<div t-if="record.country_id.raw_value and record.country_flag.raw_value">
|
|
<img t-att-src="record.country_flag.raw_value"
|
|
class="o_country_flag" alt="Country"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col mx-2">
|
|
<b><field name="time_since_last_action"/></b>
|
|
<div>Last Action</div>
|
|
</div>
|
|
<div class="col mx-2">
|
|
<b><field name="visit_count"/></b>
|
|
<div>Visits</div>
|
|
</div>
|
|
<div class="col mx-2">
|
|
<b><field name="last_visited_page_id"/></b>
|
|
<div>Last Page</div>
|
|
</div>
|
|
<div id="wvisitor_visited_page" class="col mx-2">
|
|
<b><field name="page_count"/></b>
|
|
<div>Visited Pages</div>
|
|
</div>
|
|
<div class="col-3 w_visitor_kanban_actions_ungrouped">
|
|
<button name="action_send_mail" type="object"
|
|
class="btn btn-secondary border" attrs="{'invisible': [('email', '=', False)]}">
|
|
Email
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<!-- displayed in grouped mode -->
|
|
<div class="oe_kanban_details">
|
|
<div class="float-right">
|
|
<span class="fa fa-circle text-success" t-if="record.is_connected.raw_value" aria-label="Online" title="Online"/>
|
|
<span class="fa fa-circle text-danger" t-else="" aria-label="Offline" title="Offline"/>
|
|
</div>
|
|
<strong>
|
|
<img t-if="record.country_id.raw_value"
|
|
t-att-src="record.country_flag.raw_value"
|
|
class="o_country_flag" alt="Country"/>
|
|
<field name="display_name"/>
|
|
</strong>
|
|
<div class="mb-2">Active <field name="time_since_last_action"/></div>
|
|
<div>Last Page<span class="float-right font-weight-bold"><field name="last_visited_page_id"/></span></div>
|
|
<div>Visits<span class="float-right font-weight-bold"><field name="visit_count"/></span></div>
|
|
<div id="o_page_count">Visited Pages<span class="float-right font-weight-bold"><field name="page_count"/></span></div>
|
|
<div class="w_visitor_kanban_actions">
|
|
<button name="action_send_mail" type="object"
|
|
class="btn btn-secondary" attrs="{'invisible': [('email', '=', False)]}">
|
|
Email
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
</templates>
|
|
</kanban>
|
|
</field>
|
|
</record>
|
|
|
|
<record id="website_visitor_view_form" model="ir.ui.view">
|
|
<field name="name">website.visitor.view.form</field>
|
|
<field name="model">website.visitor</field>
|
|
<field name="arch" type="xml">
|
|
<form string="Website Visitor">
|
|
<header>
|
|
<button name="action_send_mail" type="object" class="btn btn-primary"
|
|
attrs="{'invisible': [('email', '=', False)]}" string="Send Email"/>
|
|
</header>
|
|
<sheet>
|
|
<div class="oe_button_box" name="button_box">
|
|
<button class="oe_stat_button o_stat_button_info" attrs="{'invisible': [('is_connected', '=', False)]}">
|
|
<i class="fa fa-fw o_button_icon fa-circle text-success"/>
|
|
<span>Connected</span>
|
|
</button>
|
|
<button class="oe_stat_button o_stat_button_info" attrs="{'invisible': [('is_connected', '=', True)]}">
|
|
<i class="fa fa-fw o_button_icon fa-circle text-danger"/>
|
|
<span>Offline</span>
|
|
</button>
|
|
<button id="w_visitor_visit_counter" class="oe_stat_button o_stat_button_info" icon="fa-globe">
|
|
<field name="visit_count" widget="statinfo" string="Visits"/>
|
|
</button>
|
|
<button name="%(website.website_visitor_page_action)d" type="action"
|
|
class="oe_stat_button"
|
|
icon="fa-tags">
|
|
<field name="visitor_page_count" widget="statinfo" string="Page Views"/>
|
|
</button>
|
|
</div>
|
|
<div class="float-right" attrs="{'invisible': [('country_id', '=', False)]}">
|
|
<field name="country_flag" widget="image_url" options='{"size": [32, 32]}'/>
|
|
</div>
|
|
<div class="oe_title">
|
|
<h1><field name="display_name"/></h1>
|
|
</div>
|
|
<group id="general_info">
|
|
<group string="Details">
|
|
<field name="active" invisible="1"/>
|
|
<field name="is_connected" invisible="1"/>
|
|
<field name="partner_id"/>
|
|
<field name="email"/>
|
|
<field name="mobile" class="o_force_ltr"/>
|
|
<field name="country_id" attrs="{'invisible': [('country_id', '=', False)]}"/>
|
|
<field name="lang_id"/>
|
|
</group>
|
|
<group id="visits" string="Visits">
|
|
<field name="website_id" groups="website.group_multi_website"/>
|
|
<field name="create_date"/>
|
|
<field name="last_connection_datetime"/>
|
|
<field name="page_ids" string="Pages" widget="many2many_tags"/>
|
|
</group>
|
|
</group>
|
|
</sheet>
|
|
</form>
|
|
</field>
|
|
</record>
|
|
|
|
<record id="website_visitor_view_tree" model="ir.ui.view">
|
|
<field name="name">website.visitor.view.tree</field>
|
|
<field name="model">website.visitor</field>
|
|
<field name="arch" type="xml">
|
|
<tree string="Web Visitors" decoration-success="is_connected" sample="1">
|
|
<field name="country_flag" widget="image_url" options='{"size": [20, 20]}' nolabel="1"/>
|
|
<field name="display_name" string="Name"/>
|
|
<field name="create_date" optional="hide"/>
|
|
<field name="last_connection_datetime"/>
|
|
<field name="lang_id"/>
|
|
<field name="country_id" optional="hide"/>
|
|
<field name="visit_count"/>
|
|
<field name="page_ids" widget="many2many_tags" string="Pages"/>
|
|
<field name="last_visited_page_id" string="Last Page" optional="hide"/>
|
|
<field name="is_connected" invisible="1"/>
|
|
<field name="email" invisible="1"/>
|
|
<button string="Email" name="action_send_mail" type="object"
|
|
icon="fa-envelope" attrs="{'invisible': [('email', '=', False)]}"/>
|
|
</tree>
|
|
</field>
|
|
</record>
|
|
|
|
<record id="website_visitor_view_search" model="ir.ui.view">
|
|
<field name="name">website.visitor.view.search</field>
|
|
<field name="model">website.visitor</field>
|
|
<field name="arch" type="xml">
|
|
<search string="Search Visitor">
|
|
<field name="name"/>
|
|
<field name="lang_id"/>
|
|
<field name="country_id"/>
|
|
<field name="visit_count"/>
|
|
<field name="page_ids"/>
|
|
<filter string="Last 7 Days" name="filter_last_7_days" domain="[('last_connection_datetime', '>', datetime.datetime.now() - datetime.timedelta(days=7))]"/>
|
|
<separator/>
|
|
<filter string="Unregistered" name="filter_type_visitor" domain="[('partner_id', '=', False)]"/>
|
|
<filter string="Contacts" name="filter_type_customer" domain="[('partner_id', '!=', False)]"/>
|
|
<separator/>
|
|
<filter string="Connected" name="filter_is_connected" domain="[('last_connection_datetime', '>', datetime.datetime.now() - datetime.timedelta(minutes=5))]"/>
|
|
<separator/>
|
|
<filter string="Archived" name="filter_is_archived" domain="[('active', '=', False)]"/>
|
|
<separator/>
|
|
<group string="Group By">
|
|
<filter string="Country" name="group_by_country" context="{'group_by': 'country_id'}"/>
|
|
<filter string="Timezone" name="group_by_timezone" context="{'group_by': 'timezone'}"/>
|
|
<filter string="Language" name="group_by_lang" context="{'group_by': 'lang_id'}"/>
|
|
<filter string="# Visits" name="group_by_visit_count" context="{'group_by': 'visit_count'}"/>
|
|
<filter string="Website" name="group_by_website_id" context="{'group_by': 'website_id'}" groups="website.group_multi_website"/>
|
|
<filter string="First Connection" name="group_by_create_date" context="{'group_by': 'create_date'}"/>
|
|
<filter string="Last Connection" name="group_by_last_connection_datetime" context="{'group_by': 'last_connection_datetime'}"/>
|
|
</group>
|
|
</search>
|
|
</field>
|
|
</record>
|
|
|
|
<record id="website_visitor_view_graph" model="ir.ui.view">
|
|
<field name="name">website.visitor.view.graph</field>
|
|
<field name="model">website.visitor</field>
|
|
<field name="arch" type="xml">
|
|
<graph string="Visitors" type="line" sample="1">
|
|
<field name="last_connection_datetime" interval="day" type="row"/>
|
|
</graph>
|
|
</field>
|
|
</record>
|
|
|
|
<record id="website_visitors_action" model="ir.actions.act_window">
|
|
<field name="name">Visitors</field>
|
|
<field name="type">ir.actions.act_window</field>
|
|
<field name="res_model">website.visitor</field>
|
|
<field name="view_mode">kanban,tree,form,graph</field>
|
|
<field name="context">{'search_default_filter_last_7_days':1}</field>
|
|
<field name="help" type="html">
|
|
<p class="o_view_nocontent_smiling_face">
|
|
Wait for visitors to come to your website to see their history.
|
|
</p>
|
|
</field>
|
|
</record>
|
|
|
|
<record id="website_visitor_track_view_tree" model="ir.ui.view">
|
|
<field name="name">website.track.view.tree</field>
|
|
<field name="model">website.track</field>
|
|
<field name="arch" type="xml">
|
|
<tree string="Visitor Views History" create="0" edit="0" sample="1">
|
|
<field name="visitor_id"/>
|
|
<field name="page_id"/>
|
|
<field name="url"/>
|
|
<field name="visit_datetime"/>
|
|
</tree>
|
|
</field>
|
|
</record>
|
|
|
|
<record id="website_visitor_track_view_graph" model="ir.ui.view">
|
|
<field name="name">website.track.view.graph</field>
|
|
<field name="model">website.track</field>
|
|
<field name="arch" type="xml">
|
|
<graph string="Visitor Views" sample="1">
|
|
<field name="url"/>
|
|
</graph>
|
|
</field>
|
|
</record>
|
|
|
|
<record id="website_visitor_view_action" model="ir.actions.act_window">
|
|
<field name="name">Views</field>
|
|
<field name="type">ir.actions.act_window</field>
|
|
<field name="res_model">website.track</field>
|
|
<field name="view_mode">tree</field>
|
|
<field name="context">{'search_default_type_url':1}</field>
|
|
<field name="view_ids" eval="[(5, 0, 0),
|
|
(0, 0, {'view_mode': 'tree', 'view_id': ref('website_visitor_track_view_tree')}),
|
|
(0, 0, {'view_mode': 'graph', 'view_id': ref('website_visitor_track_view_graph')}),
|
|
]"/>
|
|
<field name="help" type="html">
|
|
<p class="o_view_nocontent_smiling_face">
|
|
Wait for visitors to come to your website to see the pages they viewed.
|
|
</p>
|
|
</field>
|
|
</record>
|
|
|
|
<menuitem id="website_visitor_menu"
|
|
name="Visitors"
|
|
sequence="80"
|
|
parent="website.menu_website_configuration"/>
|
|
|
|
<menuitem id="menu_visitor_sub_menu" name="Visitors"
|
|
sequence="1"
|
|
parent="website_visitor_menu"
|
|
action="website.website_visitors_action"/>
|
|
<menuitem id="menu_visitor_view_menu" name="Views"
|
|
sequence="2"
|
|
parent="website_visitor_menu"
|
|
action="website.website_visitor_view_action"/>
|
|
</data></odoo>
|