Browse Source
[ADD] base_kanban_stage: Stage model and abstract logic
[ADD] base_kanban_stage: Stage model and abstract logic
* Add Kanban-compatible stage model base.kanban.stage * Add views, menu items, actions, and access controls needed to manage base.kanban.stage records * Add abstract model base.kanban.abstract that other models can inherit from to gain Kanban stage functionality * Add base Kanban view base_kanban_abstract_view_kanban, which can be customized as needed for use with models that inherit from base.kanban.abstract * Add model base.kanban.abstract.tester, which is needed for base.kanban.abstract unit tests12.0
Ted Salmon
8 years ago
committed by
ahenriquez
13 changed files with 606 additions and 0 deletions
-
108base_kanban_stage/README.rst
-
5base_kanban_stage/__init__.py
-
23base_kanban_stage/__openerp__.py
-
6base_kanban_stage/models/__init__.py
-
112base_kanban_stage/models/base_kanban_abstract.py
-
84base_kanban_stage/models/base_kanban_stage.py
-
3base_kanban_stage/security/ir.model.access.csv
-
BINbase_kanban_stage/static/description/icon.png
-
6base_kanban_stage/tests/__init__.py
-
73base_kanban_stage/tests/test_base_kanban_abstract.py
-
50base_kanban_stage/tests/test_base_kanban_stage.py
-
64base_kanban_stage/views/base_kanban_abstract.xml
-
72base_kanban_stage/views/base_kanban_stage.xml
@ -0,0 +1,108 @@ |
|||||
|
.. image:: https://img.shields.io/badge/licence-lgpl--3-blue.svg |
||||
|
:target: http://www.gnu.org/licenses/LGPL-3.0-standalone.html |
||||
|
:alt: License: LGPL-3 |
||||
|
|
||||
|
====================== |
||||
|
Kanban - Stage Support |
||||
|
====================== |
||||
|
|
||||
|
This module provides a stage model compatible with Kanban views and the |
||||
|
standard views needed to manage these stages. It also provides the |
||||
|
``base.kanban.abstract`` model, which can be inherited to add support for |
||||
|
Kanban views with stages to any other model. Lastly, it includes a base Kanban |
||||
|
view that can be extended as needed. |
||||
|
|
||||
|
Installation |
||||
|
============ |
||||
|
|
||||
|
To install this module, simply follow the standard install process. |
||||
|
|
||||
|
Configuration |
||||
|
============= |
||||
|
|
||||
|
No configuration is needed or possible. |
||||
|
|
||||
|
Usage |
||||
|
===== |
||||
|
|
||||
|
* Inherit from ``base.kanban.abstract`` to add Kanban stage functionality to |
||||
|
the child model: |
||||
|
|
||||
|
.. code-block:: python |
||||
|
|
||||
|
class MyModel(models.Model): |
||||
|
_name = 'my.model' |
||||
|
_inherit = 'base.kanban.abstract' |
||||
|
|
||||
|
* Extend the provided base Kanban view (``base_kanban_abstract_view_kanban``) |
||||
|
as needed by the child model. The base view has four ``name`` attributes |
||||
|
intended to provide convenient XPath access to different parts of the Kanban |
||||
|
card. They are ``card_dropdown_menu``, ``card_header``, ``card_body``, and |
||||
|
``card_footer``: |
||||
|
|
||||
|
.. code-block:: xml |
||||
|
|
||||
|
<record id="my_model_view_kanban" model="ir.ui.view"> |
||||
|
<field name="name">My Model - Kanban View</field> |
||||
|
<field name="model">my.model</field> |
||||
|
<field name="inherit_id" ref="base_kanban_stage.base_kanban_abstract_view_kanban"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<xpath expr="//div[@name='card_header']"> |
||||
|
<!-- Add header content here --> |
||||
|
</xpath> |
||||
|
<xpath expr="//div[@name='card_body']"> |
||||
|
<!-- Add body content here --> |
||||
|
</xpath> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
* To manage stages, go to Settings > Technical > Kanban > Stages. |
||||
|
|
||||
|
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas |
||||
|
:alt: Try me on Runbot |
||||
|
:target: https://runbot.odoo-community.org/runbot/162/9.0 |
||||
|
|
||||
|
Known Issues / Roadmap |
||||
|
====================== |
||||
|
|
||||
|
* The grouping logic used by ``base.kanban.abstract`` currently does not |
||||
|
support additional domains and alternate sort orders |
||||
|
|
||||
|
Bug Tracker |
||||
|
=========== |
||||
|
|
||||
|
Bugs are tracked on `GitHub Issues <https://github.com/OCA/server-tools/issues>`_. |
||||
|
In case of trouble, please check there if your issue has already been reported. |
||||
|
If you spotted it first, help us smash it by providing detailed and welcomed |
||||
|
feedback. |
||||
|
|
||||
|
Credits |
||||
|
======= |
||||
|
|
||||
|
Images |
||||
|
------ |
||||
|
|
||||
|
* Odoo Community Association: |
||||
|
`Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_. |
||||
|
|
||||
|
Contributors |
||||
|
------------ |
||||
|
|
||||
|
* Dave Lasley <dave@laslabs.com> |
||||
|
* Oleg Bulkin <obulkin@laslabs.com> |
||||
|
* Daniel Reis |
||||
|
|
||||
|
Maintainer |
||||
|
---------- |
||||
|
|
||||
|
.. image:: https://odoo-community.org/logo.png |
||||
|
:alt: Odoo Community Association |
||||
|
:target: https://odoo-community.org |
||||
|
|
||||
|
This module is maintained by the OCA. |
||||
|
|
||||
|
OCA, or the Odoo Community Association, is a nonprofit organization whose |
||||
|
mission is to support the collaborative development of Odoo features and |
||||
|
promote its widespread use. |
||||
|
|
||||
|
To contribute to this module, please visit http://odoo-community.org. |
@ -0,0 +1,5 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2016 LasLabs Inc. |
||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
||||
|
|
||||
|
from . import models |
@ -0,0 +1,23 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2016 LasLabs Inc. |
||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
||||
|
|
||||
|
{ |
||||
|
'name': 'Kanban - Stage Support', |
||||
|
'summary': 'Provides stage model and abstract logic for inheritance', |
||||
|
'version': '9.0.1.0.0', |
||||
|
'author': "LasLabs, Odoo Community Association (OCA)", |
||||
|
'category': 'base', |
||||
|
'depends': [ |
||||
|
'web_kanban', |
||||
|
], |
||||
|
'website': 'https://laslabs.com', |
||||
|
'license': 'LGPL-3', |
||||
|
'data': [ |
||||
|
'security/ir.model.access.csv', |
||||
|
'views/base_kanban_abstract.xml', |
||||
|
'views/base_kanban_stage.xml', |
||||
|
], |
||||
|
'installable': True, |
||||
|
'application': False, |
||||
|
} |
@ -0,0 +1,6 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2016 LasLabs Inc. |
||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
||||
|
|
||||
|
from . import base_kanban_abstract |
||||
|
from . import base_kanban_stage |
@ -0,0 +1,112 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2016 LasLabs Inc. |
||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
||||
|
|
||||
|
from openerp import api, fields, models |
||||
|
|
||||
|
|
||||
|
class BaseKanbanAbstract(models.AbstractModel): |
||||
|
'''Inherit from this class to add support for Kanban stages to your model. |
||||
|
All public properties are preceded with kanban_ in order to isolate from |
||||
|
child models, with the exception of stage_id, which is a required field in |
||||
|
the Kanban widget and must be defined as such.''' |
||||
|
|
||||
|
_name = 'base.kanban.abstract' |
||||
|
_order = 'kanban_priority desc, kanban_sequence' |
||||
|
_group_by_full = { |
||||
|
'stage_id': lambda s, *a, **k: s._read_group_stage_ids(*a, **k), |
||||
|
} |
||||
|
|
||||
|
kanban_sequence = fields.Integer( |
||||
|
default=10, |
||||
|
index=True, |
||||
|
help='Order of record in relation to other records in the same Kanban' |
||||
|
' stage and with the same priority', |
||||
|
) |
||||
|
kanban_priority = fields.Selection( |
||||
|
selection=[('0', 'Normal'), ('5', 'Medium'), ('10', 'High')], |
||||
|
index=True, |
||||
|
default='0', |
||||
|
help='The priority of the record (shown as stars in Kanban views)', |
||||
|
) |
||||
|
stage_id = fields.Many2one( |
||||
|
string='Kanban Stage', |
||||
|
comodel_name='base.kanban.stage', |
||||
|
track_visibility='onchange', |
||||
|
index=True, |
||||
|
copy=False, |
||||
|
help='The Kanban stage that this record is currently in', |
||||
|
default=lambda s: s._default_stage_id(), |
||||
|
domain=lambda s: [('res_model.model', '=', s._name)], |
||||
|
) |
||||
|
kanban_user_id = fields.Many2one( |
||||
|
string='Assigned To', |
||||
|
comodel_name='res.users', |
||||
|
index=True, |
||||
|
track_visibility='onchange', |
||||
|
help='User that the record is currently assigned to', |
||||
|
) |
||||
|
kanban_color = fields.Integer( |
||||
|
string='Color Index', |
||||
|
help='Color index to be used for the record\'s Kanban card', |
||||
|
) |
||||
|
kanban_legend_priority = fields.Text( |
||||
|
string='Priority Explanation', |
||||
|
related='stage_id.legend_priority', |
||||
|
help='Explanation text to help users understand how the priority/star' |
||||
|
' mechanism applies to this record (depends on current stage)', |
||||
|
) |
||||
|
kanban_legend_blocked = fields.Text( |
||||
|
string='Special Handling Explanation', |
||||
|
related='stage_id.legend_blocked', |
||||
|
help='Explanation text to help users understand how the special' |
||||
|
' handling status applies to this record (depends on current' |
||||
|
' stage)', |
||||
|
) |
||||
|
kanban_legend_done = fields.Text( |
||||
|
string='Ready Explanation', |
||||
|
related='stage_id.legend_done', |
||||
|
help='Explanation text to help users understand how the ready' |
||||
|
' status applies to this record (depends on current stage)', |
||||
|
) |
||||
|
kanban_legend_normal = fields.Text( |
||||
|
string='Normal Handling Explanation', |
||||
|
related='stage_id.legend_normal', |
||||
|
help='Explanation text to help users understand how the normal' |
||||
|
' handling status applies to this record (depends on current' |
||||
|
' stage)', |
||||
|
) |
||||
|
kanban_status = fields.Selection( |
||||
|
selection=[ |
||||
|
('normal', 'Normal Handling'), |
||||
|
('done', 'Ready'), |
||||
|
('blocked', 'Special Handling'), |
||||
|
], |
||||
|
string='Kanban Status', |
||||
|
default='normal', |
||||
|
track_visibility='onchange', |
||||
|
required=True, |
||||
|
copy=False, |
||||
|
help='A record can have one of several Kanban statuses, which are used' |
||||
|
' to indicate whether there are any special situations affecting' |
||||
|
' it. The exact meaning of each status is allowed to vary based' |
||||
|
' on the stage the record is in but they are roughly as follow:\n' |
||||
|
'* Normal Handling: Default status, no special situations\n' |
||||
|
'* Ready: Ready to transition to the next stage\n' |
||||
|
'* Special Handling: Blocked in some way (e.g. must be handled by' |
||||
|
' a specific user)\n' |
||||
|
) |
||||
|
|
||||
|
@api.model |
||||
|
def _default_stage_id(self): |
||||
|
return self.env['base.kanban.stage'] |
||||
|
|
||||
|
@api.multi |
||||
|
def _read_group_stage_ids( |
||||
|
self, domain=None, read_group_order=None, access_rights_uid=None |
||||
|
): |
||||
|
stage_model = self.env['base.kanban.stage'].sudo(access_rights_uid) |
||||
|
stages = stage_model.search([('res_model.model', '=', self._name)]) |
||||
|
names = [(r.id, r.display_name) for r in stages] |
||||
|
fold = {r.id: r.fold for r in stages} |
||||
|
return names, fold |
@ -0,0 +1,84 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2016 LasLabs Inc. |
||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
||||
|
|
||||
|
from openerp import api, fields, models |
||||
|
|
||||
|
|
||||
|
class BaseKanbanStage(models.Model): |
||||
|
_name = 'base.kanban.stage' |
||||
|
_description = 'Kanban Stage' |
||||
|
_order = 'res_model, sequence' |
||||
|
|
||||
|
name = fields.Char( |
||||
|
string='Stage Name', |
||||
|
translate=True, |
||||
|
required=True, |
||||
|
help='Displayed as the header for this stage in Kanban views', |
||||
|
) |
||||
|
description = fields.Text( |
||||
|
translate=True, |
||||
|
help='Short description of the stage\'s meaning/purpose', |
||||
|
) |
||||
|
sequence = fields.Integer( |
||||
|
default=1, |
||||
|
required=True, |
||||
|
index=True, |
||||
|
help='Order of stage in relation to other stages available for the' |
||||
|
' same model', |
||||
|
) |
||||
|
legend_priority = fields.Text( |
||||
|
string='Priority Explanation', |
||||
|
translate=True, |
||||
|
default='Mark a card as medium or high priority (one or two stars) to' |
||||
|
' indicate that it should be escalated ahead of others with' |
||||
|
' lower priority/star counts.', |
||||
|
help='Explanation text to help users understand how the priority/star' |
||||
|
' mechanism applies to this stage', |
||||
|
) |
||||
|
legend_blocked = fields.Text( |
||||
|
string='Special Handling Explanation', |
||||
|
translate=True, |
||||
|
default='Give a card the special handling status to indicate that it' |
||||
|
' requires handling by a special user or subset of users.', |
||||
|
help='Explanation text to help users understand how the special' |
||||
|
' handling status applies to this stage', |
||||
|
) |
||||
|
legend_done = fields.Text( |
||||
|
string='Ready Explanation', |
||||
|
translate=True, |
||||
|
default='Mark a card as ready when it has been fully processed.', |
||||
|
help='Explanation text to help users understand how the ready status' |
||||
|
' applies to this stage', |
||||
|
) |
||||
|
legend_normal = fields.Text( |
||||
|
string='Normal Handling Explanation', |
||||
|
translate=True, |
||||
|
default='This is the default status and indicates that a card can be' |
||||
|
' processed by any user working this queue.', |
||||
|
help='Explanation text to help users understand how the normal' |
||||
|
' handling status applies to this stage', |
||||
|
) |
||||
|
fold = fields.Boolean( |
||||
|
string='Collapse?', |
||||
|
help='Determines whether this stage will be collapsed down in Kanban' |
||||
|
' views', |
||||
|
) |
||||
|
res_model = fields.Many2one( |
||||
|
string='Associated Model', |
||||
|
comodel_name='ir.model', |
||||
|
required=True, |
||||
|
index=True, |
||||
|
help='The model that this Kanban stage will be used for', |
||||
|
domain=[('transient', '=', False)], |
||||
|
default=lambda s: s._default_res_model(), |
||||
|
) |
||||
|
|
||||
|
@api.model |
||||
|
def _default_res_model(self): |
||||
|
'''Useful when creating stages from a Kanban view for another model''' |
||||
|
action_id = self.env.context.get('params', {}).get('action') |
||||
|
action = self.env['ir.actions.act_window'].browse(action_id) |
||||
|
default_model = action.res_model |
||||
|
if default_model != self._name: |
||||
|
return self.env['ir.model'].search([('model', '=', default_model)]) |
@ -0,0 +1,3 @@ |
|||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink |
||||
|
access_user,Kanban Stage - User Access,model_base_kanban_stage,base.group_user,1,0,0,0 |
||||
|
access_manager,Kanban Stage - Manager Access,model_base_kanban_stage,base.group_erp_manager,1,1,1,1 |
After Width: 128 | Height: 128 | Size: 9.2 KiB |
@ -0,0 +1,6 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2016 LasLabs Inc. |
||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
||||
|
|
||||
|
from . import test_base_kanban_abstract |
||||
|
from . import test_base_kanban_stage |
@ -0,0 +1,73 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2016 LasLabs Inc. |
||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
||||
|
|
||||
|
from openerp import models |
||||
|
from openerp.tests.common import TransactionCase |
||||
|
|
||||
|
|
||||
|
class BaseKanbanAbstractTester(models.Model): |
||||
|
_name = 'base.kanban.abstract.tester' |
||||
|
_inherit = 'base.kanban.abstract' |
||||
|
|
||||
|
|
||||
|
class TestBaseKanbanAbstract(TransactionCase): |
||||
|
def setUp(self): |
||||
|
super(TestBaseKanbanAbstract, self).setUp() |
||||
|
|
||||
|
BaseKanbanAbstractTester._build_model(self.registry, self.cr) |
||||
|
self.test_model = self.env[BaseKanbanAbstractTester._name] |
||||
|
|
||||
|
test_model_type = self.env['ir.model'].create({ |
||||
|
'model': BaseKanbanAbstractTester._name, |
||||
|
'name': 'Kanban Abstract - Test Model', |
||||
|
'state': 'base', |
||||
|
}) |
||||
|
|
||||
|
test_stage_1 = self.env['base.kanban.stage'].create({ |
||||
|
'name': 'Test Stage 1', |
||||
|
'res_model': test_model_type.id, |
||||
|
}) |
||||
|
test_stage_2 = self.env['base.kanban.stage'].create({ |
||||
|
'name': 'Test Stage 2', |
||||
|
'res_model': test_model_type.id, |
||||
|
'fold': True, |
||||
|
}) |
||||
|
|
||||
|
self.id_1 = test_stage_1.id |
||||
|
self.id_2 = test_stage_2.id |
||||
|
|
||||
|
def test_read_group_stage_ids_base_case(self): |
||||
|
'''It should return a structure with the proper content''' |
||||
|
self.assertEqual( |
||||
|
self.test_model._read_group_stage_ids(), |
||||
|
( |
||||
|
[(self.id_1, 'Test Stage 1'), (self.id_2, 'Test Stage 2')], |
||||
|
{self.id_1: False, self.id_2: True}, |
||||
|
) |
||||
|
) |
||||
|
|
||||
|
def test_read_group_stage_ids_correct_associated_model(self): |
||||
|
'''It should only return info for stages with right associated model''' |
||||
|
stage_model = self.env['ir.model'].search([ |
||||
|
('model', '=', 'base.kanban.stage'), |
||||
|
]) |
||||
|
self.env['base.kanban.stage'].create({ |
||||
|
'name': 'Test Stage 3', |
||||
|
'res_model': stage_model.id, |
||||
|
}) |
||||
|
|
||||
|
self.assertEqual( |
||||
|
self.test_model._read_group_stage_ids(), |
||||
|
( |
||||
|
[(self.id_1, 'Test Stage 1'), (self.id_2, 'Test Stage 2')], |
||||
|
{self.id_1: False, self.id_2: True}, |
||||
|
) |
||||
|
) |
||||
|
|
||||
|
def test_default_stage_id(self): |
||||
|
''' It should return an empty RecordSet ''' |
||||
|
self.assertEqual( |
||||
|
self.env['base.kanban.abstract']._default_stage_id(), |
||||
|
self.env['base.kanban.stage'] |
||||
|
) |
@ -0,0 +1,50 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2016 LasLabs Inc. |
||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
||||
|
|
||||
|
from openerp.tests.common import TransactionCase |
||||
|
|
||||
|
|
||||
|
class TestBaseKanbanStage(TransactionCase): |
||||
|
def test_default_res_model_no_params(self): |
||||
|
'''It should return empty ir.model Recordset if no params in context''' |
||||
|
test_stage = self.env['base.kanban.stage'].with_context({}) |
||||
|
res_model = test_stage._default_res_model() |
||||
|
|
||||
|
self.assertFalse(res_model) |
||||
|
self.assertEqual(res_model._name, 'ir.model') |
||||
|
|
||||
|
def test_default_res_model_no_action(self): |
||||
|
'''It should return empty ir.model Recordset if no action in params''' |
||||
|
test_stage = self.env['base.kanban.stage'].with_context(params={}) |
||||
|
res_model = test_stage._default_res_model() |
||||
|
|
||||
|
self.assertFalse(res_model) |
||||
|
self.assertEqual(res_model._name, 'ir.model') |
||||
|
|
||||
|
def test_default_res_model_info_in_context(self): |
||||
|
'''It should return correct ir.model record if info in context''' |
||||
|
test_action = self.env['ir.actions.act_window'].create({ |
||||
|
'name': 'Test Action', |
||||
|
'res_model': 'res.users', |
||||
|
}) |
||||
|
test_stage = self.env['base.kanban.stage'].with_context( |
||||
|
params={'action': test_action.id}, |
||||
|
) |
||||
|
|
||||
|
self.assertEqual( |
||||
|
test_stage._default_res_model(), |
||||
|
self.env['ir.model'].search([('model', '=', 'res.users')]) |
||||
|
) |
||||
|
|
||||
|
def test_default_res_model_ignore_self(self): |
||||
|
'''It should not return ir.model record corresponding to stage model''' |
||||
|
test_action = self.env['ir.actions.act_window'].create({ |
||||
|
'name': 'Test Action', |
||||
|
'res_model': 'base.kanban.stage', |
||||
|
}) |
||||
|
test_stage = self.env['base.kanban.stage'].with_context( |
||||
|
params={'action': test_action.id}, |
||||
|
) |
||||
|
|
||||
|
self.assertFalse(test_stage._default_res_model()) |
@ -0,0 +1,64 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
|
||||
|
<!-- |
||||
|
Copyright 2016 LasLabs Inc. |
||||
|
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
||||
|
--> |
||||
|
|
||||
|
<odoo> |
||||
|
<record id="base_kanban_abstract_view_kanban" model="ir.ui.view"> |
||||
|
<field name="name">Kanban Abstract - Base Kanban View</field> |
||||
|
<field name="model">base.kanban.abstract</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<kanban default_group_by="stage_id" class="o_kanban_small_column"> |
||||
|
<field name="display_name"/> |
||||
|
<field name="kanban_color"/> |
||||
|
<field name="kanban_priority"/> |
||||
|
<field name="stage_id" options="{'group_by_tooltip': {'description': 'Stage Description:', 'legend_priority': 'Use of Stars:'}}"/> |
||||
|
<field name="kanban_sequence"/> |
||||
|
<field name="kanban_legend_blocked"/> |
||||
|
<field name="kanban_legend_normal"/> |
||||
|
<field name="kanban_legend_done"/> |
||||
|
<field name="kanban_user_id"/> |
||||
|
<templates> |
||||
|
<t t-name="kanban-box"> |
||||
|
<div t-attf-class="oe_kanban_color_#{kanban_getcolor(record.kanban_color.raw_value)} o_kanban_record oe_kanban_global_click"> |
||||
|
<div class="o_dropdown_kanban dropdown" name="card_dropdown_menu"> |
||||
|
<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 t-if="widget.editable"> |
||||
|
<a type="edit">Edit</a> |
||||
|
</li> |
||||
|
<li t-if="widget.deletable"> |
||||
|
<a type="delete">Delete</a> |
||||
|
</li> |
||||
|
<li> |
||||
|
<ul class="oe_kanban_colorpicker" data-field="kanban_color"/> |
||||
|
</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div class="o_kanban_title" name="card_header"> |
||||
|
<field name="kanban_status" widget="kanban_state_selection"/> |
||||
|
<field name="display_name"/> |
||||
|
</div> |
||||
|
<div class="oe_kanban_details" name="card_body"> |
||||
|
<!-- Child modules should add model-specific data here --> |
||||
|
</div> |
||||
|
<div class="o_kanban_footer" name="card_footer"> |
||||
|
<div class="oe_kanban_bottom_left"> |
||||
|
<field name="kanban_priority" widget="priority"/> |
||||
|
</div> |
||||
|
<div class="oe_kanban_bottom_right" t-if="record.kanban_user_id"> |
||||
|
<img t-att-src="kanban_image('res.users', 'image_small', record.kanban_user_id.raw_value)" |
||||
|
class="oe_kanban_avatar_smallbox pull-right"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</t> |
||||
|
</templates> |
||||
|
</kanban> |
||||
|
</field> |
||||
|
</record> |
||||
|
</odoo> |
@ -0,0 +1,72 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
|
||||
|
<!-- |
||||
|
Copyright 2016 LasLabs Inc. |
||||
|
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
||||
|
--> |
||||
|
|
||||
|
<odoo> |
||||
|
<record id="base_kanban_stage_view_form" model="ir.ui.view"> |
||||
|
<field name="name">Kanban Stage - Form View</field> |
||||
|
<field name="model">base.kanban.stage</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form string="Kanban Stage"> |
||||
|
<header/> |
||||
|
<sheet> |
||||
|
<group string="Core Info" name="core_info"> |
||||
|
<field name="name"/> |
||||
|
<field name="res_model"/> |
||||
|
<field name="sequence"/> |
||||
|
<field name="fold"/> |
||||
|
<field name="description"/> |
||||
|
</group> |
||||
|
<group string="Priority and Statuses" name="explanations"> |
||||
|
<field name="legend_priority"/> |
||||
|
<field name="legend_blocked"/> |
||||
|
<field name="legend_done"/> |
||||
|
<field name="legend_normal"/> |
||||
|
</group> |
||||
|
</sheet> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="base_kanban_stage_view_tree" model="ir.ui.view"> |
||||
|
<field name="name">Kanban Stages - Tree View</field> |
||||
|
<field name="model">base.kanban.stage</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree string="Kanban Stages"> |
||||
|
<field name="name"/> |
||||
|
<field name="res_model"/> |
||||
|
<field name="sequence"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="base_kanban_stage_view_search" model="ir.ui.view"> |
||||
|
<field name="name">Kanban Stages - Search View</field> |
||||
|
<field name="model">base.kanban.stage</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<search string="Kanban Stages"> |
||||
|
<field name="name"/> |
||||
|
<field name="res_model"/> |
||||
|
<field name="sequence"/> |
||||
|
</search> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record model="ir.actions.act_window" id="base_kanban_stage_action"> |
||||
|
<field name="name">Kanban Stages</field> |
||||
|
<field name="res_model">base.kanban.stage</field> |
||||
|
<field name="type">ir.actions.act_window</field> |
||||
|
<field name="view_type">form</field> |
||||
|
<field name="view_mode">tree,form</field> |
||||
|
</record> |
||||
|
|
||||
|
<menuitem id="base_kanban_stage_root_menu" name="Kanban" |
||||
|
parent="base.menu_custom" sequence="50"/> |
||||
|
|
||||
|
<menuitem id="base_kanban_stage_menu" name="Stages" |
||||
|
parent="base_kanban_stage_root_menu" |
||||
|
action="base_kanban_stage_action" /> |
||||
|
</odoo> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue