diff --git a/server_action_navigate/README.rst b/server_action_navigate/README.rst
new file mode 100644
index 00000000..2f8de2de
--- /dev/null
+++ b/server_action_navigate/README.rst
@@ -0,0 +1,8 @@
+=========================
+Server Actions - Navigate
+=========================
+
+.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ !! This file is generated by oca-gen-addon-readme !!
+ !! changes will be overwritten. !!
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
diff --git a/server_action_navigate/__init__.py b/server_action_navigate/__init__.py
new file mode 100644
index 00000000..0650744f
--- /dev/null
+++ b/server_action_navigate/__init__.py
@@ -0,0 +1 @@
+from . import models
diff --git a/server_action_navigate/__manifest__.py b/server_action_navigate/__manifest__.py
new file mode 100644
index 00000000..12d8164b
--- /dev/null
+++ b/server_action_navigate/__manifest__.py
@@ -0,0 +1,20 @@
+# Copyright (C) 2020 - Today: GRAP (http://www.grap.coop)
+# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+
+{
+ "name": "Server Actions - Navigate",
+ "version": "12.0.1.0.0",
+ "author": "GRAP, " "Odoo Community Association (OCA)",
+ "summary": "Navigate between any items of any Odoo Models",
+ "category": "Tools",
+ "website": "https://github.com/OCA/server-ux",
+ "license": "AGPL-3",
+ "depends": ["base"],
+ "maintainers": ["legalsylvain"],
+ "data": [
+ "security/ir.model.access.csv",
+ "views/view_ir_actions_server.xml",
+ ],
+ "demo": ["demo/ir_actions_server.xml"],
+}
diff --git a/server_action_navigate/demo/ir_actions_server.xml b/server_action_navigate/demo/ir_actions_server.xml
new file mode 100644
index 00000000..f5e0ce01
--- /dev/null
+++ b/server_action_navigate/demo/ir_actions_server.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+ See tags of Partners
+ navigate
+
+
+
+
+
+ 1
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
diff --git a/server_action_navigate/i18n/fr.po b/server_action_navigate/i18n/fr.po
new file mode 100644
index 00000000..4b7302e6
--- /dev/null
+++ b/server_action_navigate/i18n/fr.po
@@ -0,0 +1,202 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * server_action_navigate
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 12.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2020-02-25 14:25+0000\n"
+"PO-Revision-Date: 2020-02-25 14:25+0000\n"
+"Last-Translator: <>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: server_action_navigate
+#: model:ir.model.fields,field_description:server_action_navigate.field_ir_actions_server_navigate_line__action_id
+msgid "Action"
+msgstr "Action"
+
+#. module: server_action_navigate
+#: model:ir.model.fields,field_description:server_action_navigate.field_ir_actions_server__state
+msgid "Action To Do"
+msgstr "Action à effectuer"
+
+#. module: server_action_navigate
+#: selection:ir.actions.server,state:0
+msgid "Add Followers"
+msgstr "Ajouter des abonnés"
+
+#. module: server_action_navigate
+#: selection:ir.actions.server,state:0
+msgid "Create Next Activity"
+msgstr "Créer une activité "
+
+#. module: server_action_navigate
+#: selection:ir.actions.server,state:0
+msgid "Create a new Record"
+msgstr "Créer un nouvel enregistrement"
+
+#. module: server_action_navigate
+#: model:ir.model.fields,field_description:server_action_navigate.field_ir_actions_server_navigate_line__create_uid
+msgid "Created by"
+msgstr "Créé par"
+
+#. module: server_action_navigate
+#: model:ir.model.fields,field_description:server_action_navigate.field_ir_actions_server_navigate_line__create_date
+msgid "Created on"
+msgstr "Créé le"
+
+#. module: server_action_navigate
+#: model:ir.model.fields,help:server_action_navigate.field_ir_actions_server__navigate_action_id
+msgid "Define here the action used when the navigation will be executed if empty, a generic action will be used."
+msgstr "Définir ici l'action qui sera utilisé lors que la navigation sera exécutée. Si le champs est vide, une action générique sera utilisée."
+
+#. module: server_action_navigate
+#: model_terms:ir.ui.view,arch_db:server_action_navigate.view_ir_actions_server_form
+msgid "Delete Last Line"
+msgstr "Supprimer la dernière ligne"
+
+#. module: server_action_navigate
+#: model:ir.model.fields,field_description:server_action_navigate.field_ir_actions_server_navigate_line__display_name
+msgid "Display Name"
+msgstr "Nom affiché"
+
+#. module: server_action_navigate
+#: selection:ir.actions.server,state:0
+msgid "Execute Python Code"
+msgstr "Exécuter le code Python"
+
+#. module: server_action_navigate
+#: selection:ir.actions.server,state:0
+msgid "Execute several actions"
+msgstr "Exécuter plusieurs actions"
+
+#. module: server_action_navigate
+#: model:ir.model.fields,field_description:server_action_navigate.field_ir_actions_server_navigate_line__field_id
+msgid "Field"
+msgstr "Champ"
+
+#. module: server_action_navigate
+#: model:ir.model.fields,help:server_action_navigate.field_ir_actions_server_navigate_line__field_model
+msgid "For relationship fields, the technical name of the target model"
+msgstr "Pour les champs de relation, le nom technique du modèle cible"
+
+#. module: server_action_navigate
+#: model:ir.model.fields,field_description:server_action_navigate.field_ir_actions_server_navigate_line__id
+msgid "ID"
+msgstr "ID"
+
+#. module: server_action_navigate
+#: model:ir.model.fields,field_description:server_action_navigate.field_ir_actions_server_navigate_line____last_update
+msgid "Last Modified on"
+msgstr "Dernière modification le"
+
+#. module: server_action_navigate
+#: model:ir.model.fields,field_description:server_action_navigate.field_ir_actions_server_navigate_line__write_uid
+msgid "Last Updated by"
+msgstr "Dernière mise à jour par"
+
+#. module: server_action_navigate
+#: model:ir.model.fields,field_description:server_action_navigate.field_ir_actions_server_navigate_line__write_date
+msgid "Last Updated on"
+msgstr "Dernière mise à jour le"
+
+#. module: server_action_navigate
+#: model:ir.model.fields,field_description:server_action_navigate.field_ir_actions_server_navigate_line__sequence2
+msgid "Line Number"
+msgstr "Numéro de ligne"
+
+#. module: server_action_navigate
+#: model:ir.model.fields,field_description:server_action_navigate.field_ir_actions_server__max_navigate_line_model
+msgid "Max Navigate Model in lines"
+msgstr "Modèle maximum des lignes"
+
+#. module: server_action_navigate
+#: model:ir.model.fields,field_description:server_action_navigate.field_ir_actions_server__max_navigate_line_sequence
+msgid "Max Navigate sequence in lines"
+msgstr "Sequence maximum des lignes"
+
+#. module: server_action_navigate
+#: model:ir.model.fields,field_description:server_action_navigate.field_ir_actions_server_navigate_line__field_model
+msgid "Model"
+msgstr "Modèle"
+
+#. module: server_action_navigate
+#: selection:ir.actions.server,state:0
+msgid "Navigate"
+msgstr "Naviguer"
+
+#. module: server_action_navigate
+#: model:ir.model.fields,field_description:server_action_navigate.field_ir_actions_server__navigate_line_ids
+msgid "Navigate Lines"
+msgstr "Lignes de navigation"
+
+#. module: server_action_navigate
+#: model:ir.model.fields,field_description:server_action_navigate.field_ir_actions_server__navigate_action_id
+msgid "Navigation Action"
+msgstr "Action de navigation"
+
+#. module: server_action_navigate
+#: model_terms:ir.ui.view,arch_db:server_action_navigate.view_ir_actions_server_form
+msgid "Navigation Options"
+msgstr "Options de navigation"
+
+#. module: server_action_navigate
+#: model:ir.actions.server,name:server_action_navigate.actions_server_navigate_partner_2_tags
+msgid "See tags of Partners"
+msgstr "Voir les catégories des partenaires"
+
+#. module: server_action_navigate
+#: selection:ir.actions.server,state:0
+msgid "Send Email"
+msgstr "Envoyer par courriel"
+
+#. module: server_action_navigate
+#: model:ir.model.fields,field_description:server_action_navigate.field_ir_actions_server_navigate_line__sequence
+msgid "Sequence"
+msgstr "Séquence"
+
+#. module: server_action_navigate
+#: model:ir.model,name:server_action_navigate.model_ir_actions_server
+msgid "Server Action"
+msgstr "Action du serveur"
+
+#. module: server_action_navigate
+#: model:ir.model,name:server_action_navigate.model_ir_actions_server_navigate_line
+msgid "Server Actions Navigation Lines"
+msgstr "Lignes de navigation de l'action-serveur"
+
+#. module: server_action_navigate
+#: code:addons/server_action_navigate/models/ir_actions_server.py:62
+#, python-format
+msgid "The Action Server %s is not correctly set : No fields defined"
+msgstr "L'action-serveur '%d' n'est pas correctement paramétré : Aucun champ défini."
+
+#. module: server_action_navigate
+#: model:ir.model.fields,help:server_action_navigate.field_ir_actions_server__state
+msgid "Type of server action. The following values are available:\n"
+"- 'Execute Python Code': a block of python code that will be executed\n"
+"- 'Create': create a new record with new values\n"
+"- 'Update a Record': update the values of a record\n"
+"- 'Execute several actions': define an action that triggers several other server actions\n"
+"- 'Send Email': automatically send an email (Discuss)\n"
+"- 'Add Followers': add followers to a record (Discuss)\n"
+"- 'Create Next Activity': create an activity (Discuss)"
+msgstr "Type d'action serveur. Les valeurs suivantes sont disponibles:\n"
+"- 'Executer du code Python': un bloc de code python qui sera exécuté\n"
+"- 'Créer': créer un nouvel enregistrement avec de nouvelles valeurs\n"
+"- 'Mettre à jour un enregistrement': mettre à jour les valeurs d'un enregistrement\n"
+"- 'Executer plusieurs actions': définir une action qui déclenche plusieurs autres actions serveur\n"
+"- 'Envoyer E-Mail': envoyer un e-mail automatiquement (Discutez)\n"
+"- 'Ajouter Abonnés': ajouter des abonnés à un enregistrement (Discutez)\n"
+"- 'Créer une Nouvelle Activité': créer une activité (Discutez)"
+
+#. module: server_action_navigate
+#: selection:ir.actions.server,state:0
+msgid "Update the Record"
+msgstr "Mettre à jour l'enregistrement"
+
diff --git a/server_action_navigate/models/__init__.py b/server_action_navigate/models/__init__.py
new file mode 100644
index 00000000..da161f59
--- /dev/null
+++ b/server_action_navigate/models/__init__.py
@@ -0,0 +1,2 @@
+from . import ir_actions_server
+from . import ir_actions_server_navigate_line
diff --git a/server_action_navigate/models/ir_actions_server.py b/server_action_navigate/models/ir_actions_server.py
new file mode 100644
index 00000000..09ef4c5c
--- /dev/null
+++ b/server_action_navigate/models/ir_actions_server.py
@@ -0,0 +1,89 @@
+# Copyright (C) 2020 - Today: GRAP (http://www.grap.coop)
+# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+
+from odoo import _, api, fields, models
+from odoo.exceptions import UserError
+
+
+class IrActionsServer(models.Model):
+ _inherit = "ir.actions.server"
+
+ state = fields.Selection(selection_add=[("navigate", "Navigate")])
+
+ navigate_action_id = fields.Many2one(
+ string="Navigation Action",
+ comodel_name='ir.actions.act_window',
+ domain="[('res_model', '=', max_navigate_line_model)]",
+ help="Define here the action used when the navigation will be executed"
+ " if empty, a generic action will be used.")
+
+ navigate_line_ids = fields.One2many(
+ comodel_name="ir.actions.server.navigate.line",
+ string="Navigate Lines", inverse_name="action_id")
+
+ max_navigate_line_sequence = fields.Integer(
+ string='Max Navigate sequence in lines',
+ compute='_compute_max_navigate_line',
+ store=True
+ )
+
+ max_navigate_line_model = fields.Char(
+ string="Max Navigate Model in lines",
+ compute="_compute_max_navigate_line",
+ store=True)
+
+ @api.depends("navigate_line_ids", "model_id")
+ def _compute_max_navigate_line(self):
+ """Allow to know the highest sequence entered in navigate lines.
+ Then we add 1 to this value for the next sequence.
+ This value is given to the context of the o2m field in the view.
+ So when we create new navigate line, the sequence is automatically
+ added as : max_sequence + 1
+ """
+ for action in self:
+ action.max_navigate_line_sequence = (
+ max(action.mapped('navigate_line_ids.sequence') or [0]) + 1)
+ action.max_navigate_line_model =\
+ action.navigate_line_ids\
+ and action.navigate_line_ids[-1].field_model\
+ or action.model_id.model
+
+ def delete_last_line(self):
+ self.ensure_one()
+ self.navigate_line_ids[-1].unlink()
+ self.navigate_action_id = False
+
+ @api.model
+ def run_action_navigate_multi(self, action, eval_context=None):
+ IrModel = self.env['ir.model']
+ lines = action.navigate_line_ids
+ if len(lines) == 0:
+ raise UserError(_(
+ "The Action Server %s is not correctly set\n"
+ " : No fields defined"))
+ mapped_field_value = ".".join(lines.mapped("field_id.name"))
+
+ item_ids = eval_context['records'].mapped(mapped_field_value).ids
+ domain = "[('id','in',[" + ','.join(map(str, item_ids)) + "])]"
+
+ # Use Defined action if defined
+ if action.navigate_action_id:
+ return_action = action.navigate_action_id
+ result = return_action.read()[0]
+ result['domain'] = domain
+ else:
+ # Otherwise, return a default action
+ model_name = action.max_navigate_line_model
+ model = IrModel.search([('model', '=', model_name)])
+ view_mode = 'tree,form'
+ result = {
+ 'name': model.name,
+ 'domain': domain,
+ 'res_model': model_name,
+ 'target': 'current',
+ 'type': 'ir.actions.act_window',
+ 'view_mode': view_mode,
+ }
+
+ return result
diff --git a/server_action_navigate/models/ir_actions_server_navigate_line.py b/server_action_navigate/models/ir_actions_server_navigate_line.py
new file mode 100644
index 00000000..fab53268
--- /dev/null
+++ b/server_action_navigate/models/ir_actions_server_navigate_line.py
@@ -0,0 +1,31 @@
+# Copyright (C) 2020 - Today: GRAP (http://www.grap.coop)
+# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+
+from odoo import fields, models
+
+
+class IrActionsServerNavigateLine(models.Model):
+ _name = "ir.actions.server.navigate.line"
+ _description = "Server Actions Navigation Lines"
+ _order = "sequence"
+
+ sequence = fields.Integer(string="Sequence", default=9999)
+
+ sequence2 = fields.Integer(
+ related='sequence',
+ string="Line Number",
+ readonly=True,
+ store=True,
+ )
+
+ field_model = fields.Char(
+ string="Model", related="field_id.relation", store=True)
+
+ action_id = fields.Many2one(
+ comodel_name="ir.actions.server", string="Action",
+ required=True, ondelete="cascade")
+
+ field_id = fields.Many2one(
+ comodel_name="ir.model.fields", string="Field",
+ required=True)
diff --git a/server_action_navigate/readme/CONFIGURE.rst b/server_action_navigate/readme/CONFIGURE.rst
new file mode 100644
index 00000000..10aa8138
--- /dev/null
+++ b/server_action_navigate/readme/CONFIGURE.rst
@@ -0,0 +1,27 @@
+* Go to 'Setting / Technical / Actions / Server Actions'
+
+* Create a new item
+
+.. figure:: ../static/description/ir_actions_server_form.png
+
+* Set a name that will be used for the Contextual Action
+
+* choose a model
+
+* Select 'Navigate' option in the field 'Action To Do'
+
+* Then, select a field of this model. It can be a ``one2many``, ``many2many``,
+ ``many2one`` field.
+
+* You can then optionally select another fields (#2) that belong to the previous
+ selected field (#1) relation model
+
+* Once done, click on the 'Create Contextual Action' to generate a new 'More options'
+ button.
+
+
+**Extra options**
+
+* you can define groups whose members will have access to that option.
+
+* You can select an action that will be used to display the target field list.
diff --git a/server_action_navigate/readme/CONTRIBUTORS.rst b/server_action_navigate/readme/CONTRIBUTORS.rst
new file mode 100644
index 00000000..e1525ce0
--- /dev/null
+++ b/server_action_navigate/readme/CONTRIBUTORS.rst
@@ -0,0 +1 @@
+* Sylvain LE GAL (https://www.twitter.com/legalsylvain)
diff --git a/server_action_navigate/readme/DESCRIPTION.rst b/server_action_navigate/readme/DESCRIPTION.rst
new file mode 100644
index 00000000..526a6a62
--- /dev/null
+++ b/server_action_navigate/readme/DESCRIPTION.rst
@@ -0,0 +1,5 @@
+This module provides a generic tools to have the possibility to see a list of
+items associated to a given selection.
+
+For exemple, if you use the sale module, you can configure an action to see
+all the products that has been sold for a given selection of sale orders.
diff --git a/server_action_navigate/readme/USAGE.rst b/server_action_navigate/readme/USAGE.rst
new file mode 100644
index 00000000..7b5c2242
--- /dev/null
+++ b/server_action_navigate/readme/USAGE.rst
@@ -0,0 +1,10 @@
+* Go to a tree view, for a model for which you have defined a navigation action.
+
+* click on 'Action' Button
+
+.. figure:: ../static/description/sale_order_tree.png
+
+
+* then click on the name of the configured Action and see the results
+
+.. figure:: ../static/description/product_product_tree.png
diff --git a/server_action_navigate/security/ir.model.access.csv b/server_action_navigate/security/ir.model.access.csv
new file mode 100644
index 00000000..1fd5c04d
--- /dev/null
+++ b/server_action_navigate/security/ir.model.access.csv
@@ -0,0 +1,3 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+ir_actions_server_navigate_line_all,ir_actions_server_navigate_line_all,model_ir_actions_server_navigate_line,,1,0,0,0
+ir_actions_server_navigate_line_group_system,ir_actions_server_navigate_line_group_system,model_ir_actions_server_navigate_line,base.group_system,1,1,1,1
diff --git a/server_action_navigate/static/description/icon.png b/server_action_navigate/static/description/icon.png
new file mode 100644
index 00000000..3a0328b5
Binary files /dev/null and b/server_action_navigate/static/description/icon.png differ
diff --git a/server_action_navigate/static/description/index.html b/server_action_navigate/static/description/index.html
new file mode 100644
index 00000000..073274ff
--- /dev/null
+++ b/server_action_navigate/static/description/index.html
@@ -0,0 +1,434 @@
+
+
+
+
+
+
+Mass Operation Abstract
+
+
+
+
+
Mass Operation Abstract
+
+
+
+
This module provides generic tools to develop modules that process mass
+operations on any models.
Bugs are tracked on GitHub Issues.
+In case of trouble, please check there if your issue has already been reported.
+If you spotted it first, help us smashing it by providing a detailed and welcomed
+feedback.
+
Do not contact contributors directly about support or help with technical issues.
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.
+
This module is part of the OCA/server-ux project on GitHub.