From ae45dd9edc8c8aff5ccf3b3a2cb9fa572cde19cf Mon Sep 17 00:00:00 2001 From: tarteo Date: Fri, 8 Feb 2019 13:28:23 +0100 Subject: [PATCH] [ADD] web_edit_user_filter [FIX] Readme [FIX] Lint [ADD] Tests [IMP] UI/UX [IMP] Hide popover when other is opened [IMP] Add item to roadmap --- web_edit_user_filter/README.rst | 100 ++++++++ web_edit_user_filter/__init__.py | 1 + web_edit_user_filter/__manifest__.py | 22 ++ web_edit_user_filter/models/__init__.py | 1 + web_edit_user_filter/models/ir_filters.py | 23 ++ web_edit_user_filter/readme/CONTRIBUTORS.rst | 1 + web_edit_user_filter/readme/DESCRIPTION.rst | 4 + web_edit_user_filter/readme/ROADMAP.rst | 2 + web_edit_user_filter/readme/USAGE.rst | 15 ++ .../static/description/edit_facet.png | Bin 0 -> 12469 bytes web_edit_user_filter/static/src/js/backend.js | 242 ++++++++++++++++++ .../static/src/scss/backend.scss | 27 ++ .../static/src/xml/backend.xml | 30 +++ web_edit_user_filter/templates/assets.xml | 16 ++ web_edit_user_filter/tests/__init__.py | 1 + .../tests/test_edit_user_filter.py | 32 +++ 16 files changed, 517 insertions(+) create mode 100644 web_edit_user_filter/README.rst create mode 100644 web_edit_user_filter/__init__.py create mode 100644 web_edit_user_filter/__manifest__.py create mode 100644 web_edit_user_filter/models/__init__.py create mode 100644 web_edit_user_filter/models/ir_filters.py create mode 100644 web_edit_user_filter/readme/CONTRIBUTORS.rst create mode 100644 web_edit_user_filter/readme/DESCRIPTION.rst create mode 100644 web_edit_user_filter/readme/ROADMAP.rst create mode 100644 web_edit_user_filter/readme/USAGE.rst create mode 100644 web_edit_user_filter/static/description/edit_facet.png create mode 100644 web_edit_user_filter/static/src/js/backend.js create mode 100644 web_edit_user_filter/static/src/scss/backend.scss create mode 100644 web_edit_user_filter/static/src/xml/backend.xml create mode 100644 web_edit_user_filter/templates/assets.xml create mode 100644 web_edit_user_filter/tests/__init__.py create mode 100644 web_edit_user_filter/tests/test_edit_user_filter.py diff --git a/web_edit_user_filter/README.rst b/web_edit_user_filter/README.rst new file mode 100644 index 00000000..b4498972 --- /dev/null +++ b/web_edit_user_filter/README.rst @@ -0,0 +1,100 @@ +================= +Edit User Filters +================= + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png + :target: https://odoo-community.org/page/development-status + :alt: Production/Stable +.. |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_edit_user_filter + :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_edit_user_filter + :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| + +In standard Odoo you can edit user filters via the debug module. +The problem is that normal users often don't have access to this menu therefore can't adjust filters once they're saved. +This module makes this feature available for normal users with a user friendly interface. +It also adds the ability to adjust facets (a single part of the filter). + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +Edit a favourite filter: + +#. Go to a list or kanban view; +#. open the advanced search options; +#. open the 'Favorites' menu; +#. click on the pencil icon to start editing the filter. + +Edit a facet: + +#. Click on the facet; +#. a menu is now shown which allows you to remove values from the facet; +#. to cancel removal you can click outside the popover. + +.. image:: /web_edit_user_filter/static/description/edit_facet.png + :alt: Edit Facet + +Known issues / Roadmap +====================== + +* Make individual values in facets editable. + +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. + +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_edit_user_filter/__init__.py b/web_edit_user_filter/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/web_edit_user_filter/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/web_edit_user_filter/__manifest__.py b/web_edit_user_filter/__manifest__.py new file mode 100644 index 00000000..1b068468 --- /dev/null +++ b/web_edit_user_filter/__manifest__.py @@ -0,0 +1,22 @@ +# Copyright 2019 Onestein +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + 'name': 'Edit User Filters', + 'category': 'Extra Tools', + 'version': '12.0.1.0.0', + 'development_status': 'Production/Stable', + 'author': 'Onestein,Odoo Community Association (OCA)', + 'license': 'AGPL-3', + 'website': 'https://github.com/OCA/web', + 'depends': [ + 'web' + ], + 'data': [ + 'templates/assets.xml' + ], + 'qweb': [ + 'static/src/xml/backend.xml' + ], + 'installable': True, +} diff --git a/web_edit_user_filter/models/__init__.py b/web_edit_user_filter/models/__init__.py new file mode 100644 index 00000000..4c520abb --- /dev/null +++ b/web_edit_user_filter/models/__init__.py @@ -0,0 +1 @@ +from . import ir_filters diff --git a/web_edit_user_filter/models/ir_filters.py b/web_edit_user_filter/models/ir_filters.py new file mode 100644 index 00000000..05925613 --- /dev/null +++ b/web_edit_user_filter/models/ir_filters.py @@ -0,0 +1,23 @@ +# Copyright 2019 Onestein +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class IrFilters(models.Model): + _inherit = 'ir.filters' + + facet = fields.Text() + + @api.model + def get_filters(self, model, action_id=None): + res = super().get_filters(model, action_id) + ids = map(lambda f: f['id'], res) + # Browse filters that are in res + filters = self.browse(ids) + for i, res_filter in enumerate(res): + # Add the field 'facet' to the result + res[i]['facet'] = filters.filtered( + lambda f: f.id == res_filter['id'] + ).facet + return res diff --git a/web_edit_user_filter/readme/CONTRIBUTORS.rst b/web_edit_user_filter/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000..47b6403d --- /dev/null +++ b/web_edit_user_filter/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Dennis Sluijk diff --git a/web_edit_user_filter/readme/DESCRIPTION.rst b/web_edit_user_filter/readme/DESCRIPTION.rst new file mode 100644 index 00000000..68f177e9 --- /dev/null +++ b/web_edit_user_filter/readme/DESCRIPTION.rst @@ -0,0 +1,4 @@ +In standard Odoo you can edit user filters via the debug module. +The problem is that normal users often don't have access to this menu therefore can't adjust filters once they're saved. +This module makes this feature available for normal users with a user friendly interface. +It also adds the ability to adjust facets (a single part of the filter). diff --git a/web_edit_user_filter/readme/ROADMAP.rst b/web_edit_user_filter/readme/ROADMAP.rst new file mode 100644 index 00000000..3a953110 --- /dev/null +++ b/web_edit_user_filter/readme/ROADMAP.rst @@ -0,0 +1,2 @@ +* Make individual values in facets editable. +* Make saved filters easy overwritable. diff --git a/web_edit_user_filter/readme/USAGE.rst b/web_edit_user_filter/readme/USAGE.rst new file mode 100644 index 00000000..2225d9b4 --- /dev/null +++ b/web_edit_user_filter/readme/USAGE.rst @@ -0,0 +1,15 @@ +Edit a favourite filter: + +#. Go to a list or kanban view; +#. open the advanced search options; +#. open the 'Favorites' menu; +#. click on the pencil icon to start editing the filter. + +Edit a facet: + +#. Click on the facet; +#. a menu is now shown which allows you to remove values from the facet; +#. to cancel removal you can click outside the popover. + +.. image:: /web_edit_user_filter/static/description/edit_facet.png + :alt: Edit Facet diff --git a/web_edit_user_filter/static/description/edit_facet.png b/web_edit_user_filter/static/description/edit_facet.png new file mode 100644 index 0000000000000000000000000000000000000000..8932b29071a93fcec9508a80c83e1c7df40d0e72 GIT binary patch literal 12469 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 literal 0 HcmV?d00001 diff --git a/web_edit_user_filter/static/src/js/backend.js b/web_edit_user_filter/static/src/js/backend.js new file mode 100644 index 00000000..02a3373a --- /dev/null +++ b/web_edit_user_filter/static/src/js/backend.js @@ -0,0 +1,242 @@ +/* Copyright 2019 Onestein + * License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). */ + +odoo.define('web_edit_user_filter', function (require) { + "use strict"; + + var FavoriteMenu = require('web.FavoriteMenu'), + core = require('web.core'), + SearchView = require('web.SearchView'); + var qweb = core.qweb; + var _t = core._t; + + + FavoriteMenu.include({ + + /** + * Adds the facets data to the filter. + * + * @override + * @private + */ + _createFilter: function (filter) { + var facets = []; + + this.query.each(function (facet) { + var json_facet = facet.attributes; + json_facet.values = facet.get('values'); + + _.each(json_facet.values, function (value, i) { + if (typeof value.value === 'object' && + 'attrs' in value.value) { + json_facet.values[i] = { + attrs: value.value.attrs, + }; + } + }); + + if ('field' in json_facet) { + json_facet.field = { + attrs: json_facet.field.attrs, + }; + } + + facets.push(json_facet); + }); + + filter.facet = JSON.stringify(facets); + return this._super(filter); + }, + + /** + * Adds the edit button to the favourite filter menu item. + * + * @override + * @private + */ + append_filter: function (filter) { + var self = this; + var res = this._super(filter); + var key = this.key_for(filter); + this.$filters[key].append($('', { + class: 'fa fa-pencil o-edit-user-filter', + on: { + click: function (event) { + event.stopImmediatePropagation(); + self._unpackFilter(filter); + }, + }, + })); + return res; + }, + + /** + * Unpacks a saved filter and updates the search view's facets. + * + * @private + */ + _unpackFilter: function (filter) { + var self = this; + var facets = JSON.parse(filter.facet); + + var new_facets = []; + this.query.reset([]); + + _.each(facets, function (segment) { + if (segment.cat === 'groupByCategory') { + _.each(segment.values, function (value) { + var groupBy = _.find( + self.searchview.groupbysMapping, + function (mapping) { + return mapping.groupby.attrs.context === value.attrs.context; + } + ); + var eventData = { + category: 'groupByCategory', + itemId: groupBy.groupbyId, + isActive: true, + groupId: groupBy.groupId, + }; + self.trigger_up('menu_item_toggled', eventData); + }); + } else if (segment.cat === 'filterCategory') { + _.each(segment.values, function (value) { + var filterDomain = _.find( + self.searchview.filtersMapping, + function (mapping) { + return mapping.filter.attrs.domain === value.attrs.domain; + } + ); + var eventData = { + category: 'filterCategory', + itemId: filterDomain.filterId, + isActive: true, + groupId: filterDomain.groupId, + }; + self.trigger_up('menu_item_toggled', eventData); + }); + } else { + var search_widget = _.find( + self.searchview.search_fields, function (f) { + return f.attrs.name === segment.field.attrs.name; + } + ); + new_facets.push({ + category: segment.category, + field: search_widget, + values: segment.values, + }); + } + }); + + this.query.add(new_facets); + }, + }); + + SearchView.include({ + + /** + * Removes a value from a facet. + * + * @private + * @param {Backbone.Model} model + * @param {Integer|Object} value The value to remove + */ + _removeValue: function (model, value) { + var toRemove = model.values.filter(function (v) { + if (typeof v.attributes.value === 'object') { + return v.attributes.value.attrs.name === value; + } + + return v.attributes.value.toString() === value; + }); + model.values.remove(toRemove); + }, + + /** + * Renders a popover for a facet. + * + * @private + * @param {jQuery} $facet Element of the facet + * @param {Backbone.Model} model + */ + _renderPopover: function ($facet, model) { + var self = this; + + var $content = $(qweb.render('web_edit_user_filter.Popover', { + values: model.get('values'), + })); + // Cannot use Widget.events here because renderFacets is + // triggered apart from renderElement + $content.find('.list-group-item').click(function () { + self._removeValue(model, $(this).attr('data-value')); + }); + + $facet.popover({ + title: _t('Edit Facet'), + template: qweb.render('web_edit_user_filter.PopoverTemplate'), + content: $content, + container: this.$el, + html: true, + trigger: 'manual', + placement: 'bottom', + animation: false, + }); + }, + + /** + * Hides all popovers. + * + * @private + */ + _hidePopovers: function () { + this.$el.find('.popover').popover('hide'); + }, + + /** + * @override + */ + renderFacets: function () { + var self = this; + var res = this._super.apply(this, arguments); + + this.$el.find('.o-edit-user-filter-popover').remove(); + + _.each(this.input_subviews, function (input_subview) { + if (!input_subview.model || + input_subview.model.attributes.is_custom_filter) { + return; + } + + input_subview.$el.addClass('o-edit-user-filter-editable'); + self._renderPopover(input_subview.$el, input_subview.model); + + input_subview.$el.click(function () { + self._hidePopovers(); + input_subview.$el.popover('show'); + }); + }); + return res; + }, + + /** + * @override + */ + start: function () { + var self = this; + var res = this._super.apply(this, arguments); + this._proxyHidePopovers = this.proxy('_hidePopovers'); + $(document).click(this._proxyHidePopovers); + return res; + }, + + /** + * @override + */ + destroy: function () { + var res = this._super.apply(this, arguments); + $(document).unbind('click', this._proxyHidePopovers); + return res; + } + }); +}); diff --git a/web_edit_user_filter/static/src/scss/backend.scss b/web_edit_user_filter/static/src/scss/backend.scss new file mode 100644 index 00000000..eb0c8cd1 --- /dev/null +++ b/web_edit_user_filter/static/src/scss/backend.scss @@ -0,0 +1,27 @@ +/* Copyright 2019 Onestein + * License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). */ + +.o_favorites_menu { + .o-edit-user-filter { + @include o-position-absolute(50%, 30px); + margin-top: -6px; + cursor: pointer; + } +} + +.o-edit-user-filter-popover { + a { + cursor: pointer; + padding: 0.3rem 0.75rem; + font-size: 1.2rem; + + .fa-close { + padding-left: 13px; + font-size: 1.2rem; + } + } +} + +.o-edit-user-filter-editable { + cursor: pointer; +} diff --git a/web_edit_user_filter/static/src/xml/backend.xml b/web_edit_user_filter/static/src/xml/backend.xml new file mode 100644 index 00000000..de4a1668 --- /dev/null +++ b/web_edit_user_filter/static/src/xml/backend.xml @@ -0,0 +1,30 @@ + + + + diff --git a/web_edit_user_filter/templates/assets.xml b/web_edit_user_filter/templates/assets.xml new file mode 100644 index 00000000..5ba1b305 --- /dev/null +++ b/web_edit_user_filter/templates/assets.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/web_edit_user_filter/tests/__init__.py b/web_edit_user_filter/tests/__init__.py new file mode 100644 index 00000000..b069e657 --- /dev/null +++ b/web_edit_user_filter/tests/__init__.py @@ -0,0 +1 @@ +from . import test_edit_user_filter diff --git a/web_edit_user_filter/tests/test_edit_user_filter.py b/web_edit_user_filter/tests/test_edit_user_filter.py new file mode 100644 index 00000000..4819d826 --- /dev/null +++ b/web_edit_user_filter/tests/test_edit_user_filter.py @@ -0,0 +1,32 @@ +# Copyright 2019 Onestein +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.tests.common import SingleTransactionCase, post_install + + +@post_install(True) +class TestEditUserFilter(SingleTransactionCase): + def test_filter_facet_inclusion(self): + self.env['ir.filters'].create({ + 'name': 'any2', + 'model_id': 'ir.filters', + 'domain': '[]', + 'facet': 'test2' + }) + new_filter = self.env['ir.filters'].create({ + 'name': 'any', + 'model_id': 'ir.filters', + 'domain': '[]', + 'facet': 'test' + }) + res = self.env['ir.filters'].get_filters('ir.filters') + self.assertTrue('facet' in res[0]) + self.assertEqual( + list( + filter( + lambda f: f['id'] == new_filter.id, + res + ) + )[0]['facet'], + 'test' + )