diff --git a/web_tree_duplicate/README.rst b/web_tree_duplicate/README.rst
new file mode 100644
index 000000000..a3e5c704d
--- /dev/null
+++ b/web_tree_duplicate/README.rst
@@ -0,0 +1,116 @@
+===========================
+Tree View Duplicate Records
+===========================
+
+.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ !! This file is generated by oca-gen-addon-readme !!
+ !! changes will be overwritten. !!
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
+ :target: https://odoo-community.org/page/development-status
+ :alt: Beta
+.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
+ :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
+ :alt: License: AGPL-3
+.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github
+ :target: https://github.com/OCA/web/tree/12.0/web_tree_duplicate
+ :alt: OCA/web
+.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
+ :target: https://translation.odoo-community.org/projects/web-12-0/web-12-0-web_tree_duplicate
+ :alt: Translate me on Weblate
+.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
+ :target: https://runbot.odoo-community.org/runbot/162/12.0
+ :alt: Try me on Runbot
+
+|badge1| |badge2| |badge3| |badge4| |badge5|
+
+With this module you can duplicate records directly from the tree view.
+
+**Table of contents**
+
+.. contents::
+ :local:
+
+Configuration
+=============
+
+The duplicate option is disabled by default.
+To enable it you have to add attribute `duplicate` to the tree view.
+Set `duplicate` to `true` to enable it or `false` to (explicitly) disable it.
+
+Example:
+
+.. code-block:: xml
+
+
+
+
+ res.users
+
+
+
+ true
+
+
+
+
+
+Usage
+=====
+
+To use this module, you need to:
+
+#. Go to any tree view;
+#. select some records;
+#. open the sidebar menu and click 'Duplicate'.
+
+.. image:: /web_tree_duplicate/static/description/screenshot-duplicate.png
+
+Bug Tracker
+===========
+
+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.
+
+Credits
+=======
+
+Authors
+~~~~~~~
+
+* Onestein
+
+Contributors
+~~~~~~~~~~~~
+
+* Dennis Sluijk
+
+Maintainers
+~~~~~~~~~~~
+
+This module is maintained by the OCA.
+
+.. image:: https://odoo-community.org/logo.png
+ :alt: Odoo Community Association
+ :target: https://odoo-community.org
+
+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.
+
+.. |maintainer-tarteo| image:: https://github.com/tarteo.png?size=40px
+ :target: https://github.com/tarteo
+ :alt: tarteo
+
+Current `maintainer `_:
+
+|maintainer-tarteo|
+
+This module is part of the `OCA/web `_ project on GitHub.
+
+You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
diff --git a/web_tree_duplicate/__init__.py b/web_tree_duplicate/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/web_tree_duplicate/__manifest__.py b/web_tree_duplicate/__manifest__.py
new file mode 100644
index 000000000..6a326567e
--- /dev/null
+++ b/web_tree_duplicate/__manifest__.py
@@ -0,0 +1,23 @@
+# Copyright 2019 Onestein
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+{
+ 'name': 'Tree View Duplicate Records',
+ 'summary': 'Duplicate records directly from the tree view.',
+ 'development_status': 'Beta',
+ 'category': 'Extra Tools',
+ 'version': '12.0.1.0.0',
+ 'author': 'Onestein, Odoo Community Association (OCA)',
+ 'license': 'AGPL-3',
+ 'website': 'https://github.com/OCA/web',
+ 'depends': [
+ 'web'
+ ],
+ 'data': [
+ 'templates/assets.xml'
+ ],
+ 'demo': [
+ 'demo/res_users_view.xml'
+ ],
+ 'maintainers': ['tarteo']
+}
diff --git a/web_tree_duplicate/demo/res_users_view.xml b/web_tree_duplicate/demo/res_users_view.xml
new file mode 100644
index 000000000..2dc56661c
--- /dev/null
+++ b/web_tree_duplicate/demo/res_users_view.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+ res.users
+
+
+
+ true
+
+
+
+
diff --git a/web_tree_duplicate/readme/CONFIGURE.rst b/web_tree_duplicate/readme/CONFIGURE.rst
new file mode 100644
index 000000000..d10c31333
--- /dev/null
+++ b/web_tree_duplicate/readme/CONFIGURE.rst
@@ -0,0 +1,20 @@
+The duplicate option is disabled by default.
+To enable it you have to add attribute `duplicate` to the tree view.
+Set `duplicate` to `true` to enable it or `false` to (explicitly) disable it.
+
+Example:
+
+.. code-block:: xml
+
+
+
+
+ res.users
+
+
+
+ true
+
+
+
+
diff --git a/web_tree_duplicate/readme/CONTRIBUTORS.rst b/web_tree_duplicate/readme/CONTRIBUTORS.rst
new file mode 100644
index 000000000..47b6403d0
--- /dev/null
+++ b/web_tree_duplicate/readme/CONTRIBUTORS.rst
@@ -0,0 +1 @@
+* Dennis Sluijk
diff --git a/web_tree_duplicate/readme/DESCRIPTION.rst b/web_tree_duplicate/readme/DESCRIPTION.rst
new file mode 100644
index 000000000..cb705a9dc
--- /dev/null
+++ b/web_tree_duplicate/readme/DESCRIPTION.rst
@@ -0,0 +1 @@
+With this module you can duplicate records directly from the tree view.
diff --git a/web_tree_duplicate/readme/USAGE.rst b/web_tree_duplicate/readme/USAGE.rst
new file mode 100644
index 000000000..da78115c2
--- /dev/null
+++ b/web_tree_duplicate/readme/USAGE.rst
@@ -0,0 +1,7 @@
+To use this module, you need to:
+
+#. Go to any tree view;
+#. select some records;
+#. open the sidebar menu and click 'Duplicate'.
+
+.. image:: /web_tree_duplicate/static/description/screenshot-duplicate.png
diff --git a/web_tree_duplicate/static/description/screenshot-duplicate.png b/web_tree_duplicate/static/description/screenshot-duplicate.png
new file mode 100644
index 000000000..28fb3ac40
Binary files /dev/null and b/web_tree_duplicate/static/description/screenshot-duplicate.png differ
diff --git a/web_tree_duplicate/static/src/js/backend.js b/web_tree_duplicate/static/src/js/backend.js
new file mode 100644
index 000000000..0e08e9a33
--- /dev/null
+++ b/web_tree_duplicate/static/src/js/backend.js
@@ -0,0 +1,101 @@
+/* Copyright 2019 Onestein
+ * License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). */
+
+odoo.define('web_tree_duplicate', function (require) {
+ "use strict";
+ var core = require('web.core');
+ var _t = core._t;
+ var ListController = require('web.ListController');
+ var ListView = require('web.ListView');
+ var search_inputs = require('web.search_inputs');
+
+
+ ListView.include({
+
+ /**
+ * @override
+ */
+ init: function () {
+ this._super.apply(this, arguments);
+ var sidebarDuplicate = false;
+ if ('duplicate' in this.arch.attrs) {
+ sidebarDuplicate = _.str.toBool(this.arch.attrs.duplicate);
+ }
+ this.controllerParams.sidebarDuplicate = sidebarDuplicate;
+ },
+ });
+
+ ListController.include({
+
+ /**
+ * @override
+ */
+ init: function (parent, model, renderer, params) {
+ this._super.apply(this, arguments);
+ this.sidebarDuplicate = params.sidebarDuplicate;
+ },
+
+ /**
+ * Add the Duplicate button to the sidebar.
+ *
+ * @override
+ */
+ renderSidebar: function () {
+ var res = this._super.apply(this, arguments);
+ if (this.hasSidebar && this.sidebarDuplicate) {
+ this.sidebar._addItems('other', [{
+ label: _t('Duplicate'),
+ callback: this._onDuplicateSelectedRecords.bind(this),
+ }]);
+ }
+ return res;
+ },
+
+ /**
+ * This function is triggered when the Duplicate button is clicked.
+ *
+ * @private
+ */
+ _onDuplicateSelectedRecords: function () {
+ this._duplicateRecords(this.selectedRecords);
+ },
+
+ /**
+ * Duplicate records.
+ *
+ * @param {Array} ids Ids of records to duplicate
+ * @private
+ * @returns {jQuery.Deferred}
+ */
+ _duplicateRecords: function (ids) {
+ var self = this;
+ var done = [];
+ _.each(ids, function (id) {
+ done.push(self.model.duplicateRecord(id));
+ });
+ return $.when.apply($, done).done(function () {
+ var dataPoints = arguments;
+ var ids = _.map(dataPoints, function (dataPoint) {
+ return self.model.localData[dataPoint].res_id;
+ });
+ var filter = {
+ attrs: {
+ domain: JSON.stringify([['id', 'in', ids]]),
+ string: _t('Duplicated Records')
+ }
+ }
+ var filterWidget = new search_inputs.Filter(filter);
+
+ var filterGroup = new search_inputs.FilterGroup(
+ [filterWidget],
+ self.searchView,
+ self.searchView.intervalMapping,
+ self.searchView.periodMapping
+ );
+
+ var facet = filterGroup.make_facet([filterGroup.make_value(filter)]);
+ self.searchView.query.add([facet]);
+ });
+ },
+ });
+});
diff --git a/web_tree_duplicate/templates/assets.xml b/web_tree_duplicate/templates/assets.xml
new file mode 100644
index 000000000..289c2334f
--- /dev/null
+++ b/web_tree_duplicate/templates/assets.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+