From 8db04e2e1252d43dd1c01c74938dfa7f274e0ca6 Mon Sep 17 00:00:00 2001 From: Florent THOMAS Date: Thu, 10 Feb 2022 23:41:48 +0100 Subject: [PATCH] IMP: Add single menu for content browsing * Categories and content are now available and browsable in a single menu. * Navigation helps user to find content easily * Cleanups for pylint and flake --- document_page/__manifest__.py | 55 +++-- document_page/models/document_page.py | 169 +++++++++------- document_page/readme/CONTRIBUTORS.rst | 2 + .../static/src/js/document_page_kanban.js | 28 +++ document_page/views/document_menus.xml | 26 +++ document_page/views/document_page.xml | 111 +++++----- document_page/views/document_page_assets.xml | 17 +- .../views/document_page_category.xml | 191 ++++++++++++++---- 8 files changed, 398 insertions(+), 201 deletions(-) create mode 100644 document_page/static/src/js/document_page_kanban.js create mode 100644 document_page/views/document_menus.xml diff --git a/document_page/__manifest__.py b/document_page/__manifest__.py index e2432190..47bc367d 100644 --- a/document_page/__manifest__.py +++ b/document_page/__manifest__.py @@ -3,36 +3,31 @@ { - 'name': 'Document Page', - 'version': '12.0.1.3.0', - 'category': 'Knowledge Management', - 'author': 'OpenERP SA, Odoo Community Association (OCA)', - 'images': [ - 'images/category_list.png', - 'images/create_category.png', - 'images/page_list.png', - 'images/create_page.png', - 'images/customer_invoice.jpeg', - 'images/page_history.png', + "name": "Documentation Page", + "version": "12.0.1.4.0", + "category": "Knowledge Management", + "author": "OpenERP SA, Odoo Community Association (OCA)", + "images": [ + "images/category_list.png", + "images/create_category.png", + "images/page_list.png", + "images/create_page.png", + "images/customer_invoice.jpeg", + "images/page_history.png", ], - 'website': 'https://github.com/OCA/knowledge', - 'license': 'AGPL-3', - 'depends': [ - 'mail', - 'knowledge', - ], - 'data': [ - 'security/document_page_security.xml', - 'security/ir.model.access.csv', - 'wizard/document_page_create_menu.xml', - 'wizard/document_page_show_diff.xml', - 'views/document_page.xml', - 'views/document_page_category.xml', - 'views/document_page_history.xml', - 'views/document_page_assets.xml', - 'views/report_document_page.xml', - ], - 'demo': [ - 'demo/document_page.xml' + "website": "https://github.com/OCA/knowledge", + "license": "AGPL-3", + "depends": ["mail", "knowledge"], + "data": [ + "security/document_page_security.xml", + "security/ir.model.access.csv", + "wizard/document_page_create_menu.xml", + "wizard/document_page_show_diff.xml", + "views/document_page.xml", + "views/document_page_category.xml", + "views/document_page_history.xml", + "views/document_page_assets.xml", + "views/report_document_page.xml", ], + "demo": ["demo/document_page.xml"], } diff --git a/document_page/models/document_page.py b/document_page/models/document_page.py index 84cb012c..56582c3d 100644 --- a/document_page/models/document_page.py +++ b/document_page/models/document_page.py @@ -1,7 +1,7 @@ # Copyright (C) 2004-2010 Tiny SPRL (). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import api, fields, models, _ +from odoo import _, api, fields, models from odoo.exceptions import ValidationError @@ -9,49 +9,46 @@ class DocumentPage(models.Model): """This class is use to manage Document.""" _name = "document.page" - _inherit = ['mail.thread', 'mail.activity.mixin'] + _inherit = ["mail.thread", "mail.activity.mixin"] _description = "Document Page" - _order = 'name' + _parent_name = "parent_id" + _parent_store = True + _rec_name = "complete_name" + _order = "type, sequence, complete_name" - name = fields.Char('Title', required=True) + name = fields.Char("Title", required=True) type = fields.Selection( - [('content', 'Content'), ('category', 'Category')], - 'Type', + [("content", "Content"), ("category", "Category")], + "Type", help="Page type", - default="content" + default="content", ) active = fields.Boolean(default=True) parent_id = fields.Many2one( - 'document.page', - 'Category', - domain=[('type', '=', 'category')] - ) - child_ids = fields.One2many( - 'document.page', - 'parent_id', - 'Children' + "document.page", "Category", domain=[("type", "=", "category")] ) + child_ids = fields.One2many("document.page", "parent_id", "Children") content = fields.Text( "Content", - compute='_compute_content', - inverse='_inverse_content', - search='_search_content', + compute="_compute_content", + inverse="_inverse_content", + search="_search_content", required=True, copy=True, ) # no-op computed field draft_name = fields.Char( - string='Name', - help='Name for the changes made', + string="Name", + help="Name for the changes made", compute=lambda x: x, inverse=lambda x: x, ) # no-op computed field draft_summary = fields.Char( - string='Summary', - help='Describe the changes made', + string="Summary", + help="Describe the changes made", compute=lambda x: x, inverse=lambda x: x, ) @@ -59,58 +56,88 @@ class DocumentPage(models.Model): template = fields.Html( "Template", help="Template that will be used as a content template " - "for all new page of this category.", + "for all new page of this category.", ) history_head = fields.Many2one( - 'document.page.history', - 'HEAD', - compute='_compute_history_head', + "document.page.history", + "HEAD", + compute="_compute_history_head", store=True, auto_join=True, ) history_ids = fields.One2many( - 'document.page.history', - 'page_id', - 'History', - order='create_date DESC', - readonly=True, - ) - menu_id = fields.Many2one( - 'ir.ui.menu', - "Menu", + "document.page.history", + "page_id", + "History", + order="create_date DESC", readonly=True, ) + menu_id = fields.Many2one("ir.ui.menu", "Menu", readonly=True,) content_date = fields.Datetime( - 'Last Contribution Date', - related='history_head.create_date', + "Last Contribution Date", + related="history_head.create_date", store=True, index=True, readonly=True, ) content_uid = fields.Many2one( - 'res.users', - 'Last Contributor', - related='history_head.create_uid', + "res.users", + "Last Contributor", + related="history_head.create_uid", store=True, index=True, readonly=True, ) company_id = fields.Many2one( - 'res.company', - 'Company', - help='If set, page is accessible only from this company', + "res.company", + "Company", + help="If set, page is accessible only from this company", index=True, - ondelete='cascade', + ondelete="cascade", ) backend_url = fields.Char( - string='Backend URL', - help='Use it to link resources univocally', - compute='_compute_backend_url', + string="Backend URL", + help="Use it to link resources univocally", + compute="_compute_backend_url", ) - @api.depends('menu_id', 'parent_id.menu_id') + sequence = fields.Integer( + string="Sequence", default=10, help="Used to organise the category." + ) + + parent_path = fields.Char(index=True) + complete_name = fields.Char( + "Complete Name", compute="_compute_complete_name", store=True + ) + + image = fields.Binary("Image", attachment=True,) + + color = fields.Integer(string="Color Index") + + @api.multi + def write(self, vals): + child_ids = self + if vals.get("color", False) and len(vals) == 1: + child_ids = self.search( + [("type", "=", "category"), + ("parent_id", "child_of", self.ids)] + ) + res = super(DocumentPage, child_ids).write(vals) + return res + + @api.depends("name", "parent_id.complete_name") + def _compute_complete_name(self): + for category in self: + if category.parent_id: + category.complete_name = "{} / {}".format( + category.parent_id.complete_name, category.name, + ) + else: + category.complete_name = category.name + + @api.depends("menu_id", "parent_id.menu_id") def _compute_backend_url(self): - tmpl = '/web#id={}&model=document.page&view_type=form' + tmpl = "/web#id={}&model=document.page&view_type=form" for rec in self: url = tmpl.format(rec.id) # retrieve action @@ -120,13 +147,13 @@ class DocumentPage(models.Model): action = parent.menu_id.action parent = parent.parent_id if action: - url += '&action={}'.format(action.id) + url += "&action={}".format(action.id) rec.backend_url = url - @api.constrains('parent_id') + @api.constrains("parent_id") def _check_parent_id(self): if not self._check_recursion(): - raise ValidationError(_('You cannot create recursive categories.')) + raise ValidationError(_("You cannot create recursive categories.")) @api.multi def _get_page_index(self, link=True): @@ -135,7 +162,7 @@ class DocumentPage(models.Model): index = [] for subpage in self.child_ids: index += ["
  • " + subpage._get_page_index() + "
  • "] - r = '' + r = "" if link: r = '{}'.format(self.backend_url, self.name) if index: @@ -143,35 +170,37 @@ class DocumentPage(models.Model): return r @api.multi - @api.depends('history_head') + @api.depends("history_head") def _compute_content(self): for rec in self: - if rec.type == 'category': + if rec.type == "category": rec.content = rec._get_page_index(link=False) else: if rec.history_head: rec.content = rec.history_head.content else: # html widget's default, so it doesn't trigger ghost save - rec.content = '


    ' + rec.content = "


    " @api.multi def _inverse_content(self): for rec in self: - if rec.type == 'content' and \ - rec.content != rec.history_head.content: - rec._create_history({ - 'name': rec.draft_name, - 'summary': rec.draft_summary, - 'content': rec.content, - }) + if rec.type == "content" \ + and rec.content != rec.history_head.content: + rec._create_history( + { + "name": rec.draft_name, + "summary": rec.draft_summary, + "content": rec.content, + } + ) @api.multi def _search_content(self, operator, value): - return [('history_head.content', operator, value)] + return [("history_head.content", operator, value)] @api.multi - @api.depends('history_ids') + @api.depends("history_ids") def _compute_history_head(self): for rec in self: if rec.history_ids: @@ -180,20 +209,20 @@ class DocumentPage(models.Model): @api.multi def _create_history(self, vals): self.ensure_one() - history = self.env['document.page.history'] - vals['page_id'] = self.id + history = self.env["document.page.history"] + vals["page_id"] = self.id return history.create(vals) @api.onchange("parent_id") def _onchange_parent_id(self): """We Set it the right content to the new parent.""" - if not self.content or self.content == '


    ': + if not self.content or self.content == "


    ": if self.parent_id and self.parent_id.type == "category": - self.content = self.parent_id.template + self.content = self.parent_id.template @api.multi def unlink(self): - menus = self.mapped('menu_id') + menus = self.mapped("menu_id") res = super().unlink() menus.unlink() return res diff --git a/document_page/readme/CONTRIBUTORS.rst b/document_page/readme/CONTRIBUTORS.rst index f8ecb210..3c2e43da 100644 --- a/document_page/readme/CONTRIBUTORS.rst +++ b/document_page/readme/CONTRIBUTORS.rst @@ -8,3 +8,5 @@ * `Tecnativa `_: * Víctor Martínez + +* Florent THOMAS diff --git a/document_page/static/src/js/document_page_kanban.js b/document_page/static/src/js/document_page_kanban.js new file mode 100644 index 00000000..18af8b41 --- /dev/null +++ b/document_page/static/src/js/document_page_kanban.js @@ -0,0 +1,28 @@ +odoo.define("document_page.update_kanban", function(require) { + "use strict"; + + var KanbanRecord = require("web.KanbanRecord"); + + KanbanRecord.include({ + // -------------------------------------------------------------------------- + // Private + // -------------------------------------------------------------------------- + + /** + * @override + * @private + */ + _openRecord: function() { + if ( + this.modelName === "document.page" && + this.$(".o_document_page_kanban_boxes a").length + ) { + this.$(".o_document_page_kanban_boxes a") + .first() + .click(); + } else { + this._super.apply(this, arguments); + } + } + }); +}); diff --git a/document_page/views/document_menus.xml b/document_page/views/document_menus.xml new file mode 100644 index 00000000..3caf9bb4 --- /dev/null +++ b/document_page/views/document_menus.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + diff --git a/document_page/views/document_page.xml b/document_page/views/document_page.xml index d30d419e..bb81201d 100644 --- a/document_page/views/document_page.xml +++ b/document_page/views/document_page.xml @@ -1,4 +1,4 @@ - + @@ -9,9 +9,9 @@ 100 - - - + + + @@ -22,12 +22,12 @@ document.page - - - - - - + + + + + + @@ -41,27 +41,27 @@
    - +

    - +

    - +
    - - - - - + + + + + @@ -72,20 +72,20 @@ - - - - - + + + + +
    - - - + + +
    @@ -96,11 +96,11 @@ document.page
    - +

    - +

    - + @@ -111,15 +111,14 @@ document.page - - - - + + + + - - - + + + @@ -134,8 +133,8 @@ {'default_type': 'content'} form tree,form - - + +

    Click to create a new web page. @@ -144,40 +143,26 @@ - + tree - - + + - + form - - + + - + - + - + diff --git a/document_page/views/document_page_assets.xml b/document_page/views/document_page_assets.xml index b85b0e06..a192ea4d 100644 --- a/document_page/views/document_page_assets.xml +++ b/document_page/views/document_page_assets.xml @@ -1,9 +1,20 @@ - + -