[ADD] project: onboarding tour

Also:
 - creation of a (archived by default) sample project with tasks, that the
   user can activate to discover the project app.
 - improvement of the simplified form view to create a new project
This commit is contained in:
Fabien Pinckaers
2016-06-16 14:59:41 +02:00
committed by Aaron Bohy
parent 3c319b2b8b
commit ad0bc9adf2
9 changed files with 140 additions and 26 deletions
+2
View File
@@ -17,6 +17,7 @@
'resource',
'web_kanban',
'web_planner',
'web_tour',
],
'description': """
Track multi-level projects, tasks, work done on tasks
@@ -44,6 +45,7 @@ Dashboard / Reports for Project Management will include:
'res_config_view.xml',
'views/project.xml',
'project_dashboard.xml',
'tour_view.xml',
'web_planner_data.xml',
'project_mail_template_data.xml',
],
+30 -4
View File
@@ -129,9 +129,11 @@ class project(osv.osv):
def _get_visibility_selection(self, cr, uid, context=None):
""" Overriden in portal_project to offer more options """
return [('portal', _('Customer project')),
('employees', _('All employees')),
('followers', _('Private: followers only'))]
return [
('employees', _('Visible by all employees')),
('followers', _('On invitation only')),
('portal', _('Shared with a customer'))
]
def attachment_tree_view(self, cr, uid, ids, context):
task_ids = self.pool.get('project.task').search(cr, uid, [('project_id', 'in', ids)])
@@ -157,6 +159,27 @@ class project(osv.osv):
'context': "{'default_res_model': '%s','default_res_id': %d}" % (self._name, res_id)
}
def activate_sample_project(self, cr, uid, context=None):
""" Unarchives the sample project 'project.project_project_data' and
reloads the project dashboard """
# Unarchive sample project
data_obj = self.pool.get('ir.model.data')
proj_id = data_obj.xmlid_to_res_id(cr, uid, 'project.project_project_data')
if proj_id:
self.browse(cr, uid, proj_id, context=context).write({'active': True})
# Change the help message on the action (no more activate project)
act_id = data_obj.xmlid_to_res_id(cr, uid, 'project.open_view_project_all')
action = None
if act_id:
act_window_obj = self.pool.get('ir.actions.act_window')
act_window_obj.write(cr, SUPERUSER_ID, [act_id], {
"help": _('''<p class="oe_view_nocontent_create">Click to create a new project.</p>''')
}, context=context)
action = act_window_obj.read(cr, uid, [act_id])[0]
# Reload the dashboard
return action
def _get_favorite(self, cr, uid, ids, name, args, context=None):
return dict((project.id, uid in project.favorite_user_ids.ids) for project in self.browse(cr, uid, ids, context=context))
@@ -195,7 +218,7 @@ class project(osv.osv):
"with Tasks (or optionally Issues if the Issue Tracker module is installed)."),
'alias_model': fields.selection(_alias_models, "Alias Model", select=True, required=True,
help="The kind of document created when an email is received on this project's email alias"),
'privacy_visibility': fields.selection(_visibility_selection, 'Privacy / Visibility', required=True,
'privacy_visibility': fields.selection(_visibility_selection, 'Privacy', required=True,
help="Holds visibility of the tasks or issues that belong to the current project:\n"
"- Portal : employees see everything;\n"
" if portal is activated, portal users see the tasks or issues followed by\n"
@@ -350,6 +373,9 @@ class project(osv.osv):
self.write(cr, SUPERUSER_ID, not_fav_project_ids, {'favorite_user_ids': [(4, uid)]}, context=context)
self.write(cr, SUPERUSER_ID, favorite_project_ids, {'favorite_user_ids': [(3, uid)]}, context=context)
@api.multi
def close_dialog(self):
return {'type': 'ir.actions.act_window_close'}
class task(osv.osv):
_name = "project.task"
+16 -8
View File
@@ -4,19 +4,27 @@
<field name="model">project.project</field>
<field name="arch" type="xml">
<form string="Project">
<sheet string="Project">
<div class="oe_title">
<h1>
<field name="name" placeholder="Project Name"/>
</h1>
</div>
</sheet>
<sheet>
<group>
<field name="name" class="o_project_name oe_inline"
string="Project Name" placeholder="e.g. Office Party"/>
<label for="alias_name" string="Choose a Project Email" attrs="{'invisible': [('alias_domain', '=', False)]}"/>
<div name="alias_def" attrs="{'invisible': [('alias_domain', '=', False)]}">
<field name="alias_name" class="oe_inline"/>@<field name="alias_domain" class="oe_inline" readonly="1"/>
</div>
</group>
<footer>
<button string="Create" name="close_dialog" type="object" class="btn-primary"/>
<button string="Discard" class="btn-default" special="cancel"/>
</footer>
</sheet>
</form>
</field>
</record>
<record id="open_create_project" model="ir.actions.act_window">
<field name="name">Create Project</field>
<field name="name">Create a Project</field>
<field name="res_model">project.project</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
+1
View File
@@ -115,6 +115,7 @@
<field name="name">Start here to discover Odoo</field>
<field name="privacy_visibility">followers</field>
<field name="user_id" ref="base.user_root"/>
<field name="active" eval="False"/>
<field name="alias_model">project.task</field>
<field name="alias_name">discover</field>
<field name="alias_model_id" ref="model_project_task"/>
+11 -9
View File
@@ -11,7 +11,7 @@
<field name="auto_delete" eval="True"/>
<field name="scheduled_date">${(datetime.datetime.now() + relativedelta(days=3)).strftime('%Y-%m-%d %H:%M')}</field>
<field name="body_html" ><![CDATA[
% set last_created_project = user.env['project.project'].search([], order="create_date desc")[0]
% set last_created_project = user.env['project.project'].search([('alias_id','<>',False)], order="create_date desc")[0]
<div style="margin: 10px auto;">
<table cellspacing="0" cellpadding="0" style="width:100%;">
@@ -35,14 +35,16 @@
<p dir="ltr" style="margin-top:0pt;margin-bottom:8pt;">
<span style="font-size:13px;font-weight:bold;">What’s next?</span></p>
<ul style="margin-top:0pt;margin-bottom:0pt;font-size:13px;list-style-type:disc;">
<li dir="ltr">
<p dir="ltr" style="margin-top:0pt;margin-bottom:0pt;">
<span>Try creating a task by sending an email to </span>
<a href="mailto:${last_created_project.alias_id.name_get()[0][1] if last_created_project.alias_id.alias_domain else user.company_id.email}">
<span style="font-weight:bold; text-decoration:underline;">${last_created_project.alias_id.name_get()[0][1] if last_created_project.alias_id.alias_domain else user.company_id.email}</span>
</a>
</p>
</li>
% if last_created_project:
<li dir="ltr">
<p dir="ltr" style="margin-top:0pt;margin-bottom:0pt;">
<span>Try creating a task by sending an email to </span>
<a href="mailto:${last_created_project.alias_id.name_get()[0][1] if last_created_project.alias_id.alias_domain else user.company_id.email}">
<span style="font-weight:bold; text-decoration:underline;">${last_created_project.alias_id.name_get()[0][1] if last_created_project.alias_id.alias_domain else user.company_id.email}</span>
</a>
</p>
</li>
% endif
<li dir="ltr">
<p dir="ltr" style="margin-top:0pt;margin-bottom:8pt;">
<span><a href="/web#view_type=list&model=res.users&action=base.action_res_users">
+14 -5
View File
@@ -53,6 +53,7 @@
<field name="res_model">project.task</field>
<field name="view_mode">kanban,tree,form,calendar,pivot,graph</field>
<field name="context">{
'group_by': 'stage_id',
'search_default_project_id': [active_id],
'default_project_id': active_id,
}</field>
@@ -182,6 +183,14 @@
</field>
</record>
<record id="activate_sample_project" model="ir.actions.server">
<field name="name">Activate Sample Project</field>
<field name="model_id" ref="project.model_project_project"/>
<field name="code">
action = self.activate_sample_project(cr, uid, context=context)
</field>
</record>
<record id="open_view_project_all" model="ir.actions.act_window">
<field name="name">Projects</field>
<field name="res_model">project.project</field>
@@ -189,11 +198,11 @@
<field name="domain">[]</field>
<field name="view_mode">kanban,form</field>
<field name="search_view_id" ref="view_project_project_filter"/>
<field name="target">main</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Create a new project.
</p><p>
Organize your activities (plan tasks, track issues, invoice timesheets) for internal, personal or customer projects.
Click to create a new project.<br/>
<i>Or <a type="action" name="%(project.activate_sample_project)d">activate a sample project</a> to play with.</i>
</p>
</field>
</record>
@@ -221,7 +230,7 @@
<field name="model">project.task</field>
<field eval="2" name="priority"/>
<field name="arch" type="xml">
<form string="Project">
<form string="Task" class="o_form_project_tasks">
<header>
<field name="stage_id" widget="statusbar" clickable="True"
options="{'fold_field': 'fold'}"/>
@@ -290,7 +299,7 @@
<field name="name">project.task.kanban</field>
<field name="model">project.task</field>
<field name="arch" type="xml">
<kanban default_group_by="stage_id" class="o_kanban_small_column" on_create="quick_create">
<kanban class="o_kanban_small_column o_kanban_project_tasks" on_create="quick_create">
<field name="color"/>
<field name="priority"/>
<field name="stage_id" options='{"group_by_tooltip": {"description": "Stage Description", "legend_priority": "Use of stars"}}'/>
+55
View File
@@ -0,0 +1,55 @@
odoo.define('project.tour', function(require) {
"use strict";
var core = require('web.core');
var tour = require('web_tour.tour');
var _t = core._t;
tour.register('project_tour', {
'skip_enabled': true,
}, [{
trigger: '.o_app[data-menu-xmlid="base.menu_main_pm"], .oe_menu_toggler[data-menu-xmlid="base.menu_main_pm"]',
content: _t('Want a better way to <b>manage your projects</b>? <i>It starts here.</i>'),
position: 'bottom',
}, {
trigger: '.o-kanban-button-new',
extra_trigger: '.o_project_kanban',
content: _t('Let\'s create your first project.'),
position: 'right',
width: 200,
}, {
trigger: 'input.o_project_name',
content: _t('Choose a <b>project name</b>. (e.g. Website Launch, Product Development, Office Party)'),
position: 'right',
}, {
trigger: '.o_project_kanban .o_kanban_record:first-child',
content: _t('Let\'s <b>go to your project</b> and start organizing tasks.'),
position: 'right',
}, {
trigger: ".o_kanban_project_tasks .o_column_quick_create",
content: _t("Add columns to setup <b>tasks stages</b>.<br/><i>e.g. Specification &gt; Development &gt; Tests</i>"),
position: "right"
}, {
trigger: ".o-kanban-button-new",
extra_trigger: '.o_kanban_project_tasks .o_kanban_group:nth-child(2)',
content: _t("Now that the project is setup, <b>create a few tasks</b>."),
position: "right"
}, {
trigger: ".o_kanban_record:nth-child(3)",
extra_trigger: '.o_kanban_project_tasks',
content: _t("<b>Drag &amp; drop tasks</b> between columns as you work on them."),
position: "right"
}, {
trigger: ".o_kanban_record .o_priority_star",
extra_trigger: '.o_kanban_project_tasks',
content: _t("<b>Star tasks</b> to mark your favorites, the team sprint backlog, priorities, etc."),
position: "bottom"
}, {
trigger: ".breadcrumb li:not(.active):last",
extra_trigger: '.o_form_project_tasks',
content: _t("Use the breadcrumbs to <b>go back to tasks</b>."),
position: "bottom"
}]);
});
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Make the xmlid of menus required by the Project tour available in webclient -->
<record id="base.menu_main_pm" model="ir.ui.menu">
<field name="load_xmlid" eval="True"/>
</record>
<record id="menu_projects" model="ir.ui.menu">
<field name="load_xmlid" eval="True"/>
</record>
</odoo>
+1
View File
@@ -5,6 +5,7 @@
<xpath expr="." position="inside">
<link rel="stylesheet" href="/project/static/src/css/project.css"/>
<script type="text/javascript" src="/project/static/src/js/project.js"></script>
<script type="text/javascript" src="/project/static/src/js/tour.js"></script>
<link rel="stylesheet" href="/project/static/src/less/project_dashboard.less"/>
<script type="text/javascript" src="/project/static/src/js/web_planner_project.js"></script>