mirror of
https://github.com/OCA/knowledge.git
synced 2025-07-14 01:41:26 -06:00
[IMP][10.0][document_page] Change Requests and workflow improvements on documents (#155)
This commit is contained in:
parent
fe6ebff289
commit
4e446a5f34
@ -55,6 +55,7 @@ Contributors
|
||||
|
||||
* Gervais Naoussi <gervaisnaoussi@gmail.com>
|
||||
* Maxime Chambreuil <mchambreuil@ursainfosystems.com>
|
||||
* Iván Todorovich <ivan.todorovich@gmail.com>
|
||||
|
||||
Funders
|
||||
-------
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
{
|
||||
'name': 'Document Page',
|
||||
'version': '10.0.1.0.0',
|
||||
'version': '10.0.2.0.0',
|
||||
'category': 'Knowledge Management',
|
||||
'author': 'OpenERP SA, Odoo Community Association (OCA)',
|
||||
'images': [
|
||||
@ -26,9 +26,12 @@
|
||||
'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',
|
||||
'security/document_page_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'data/document_page.xml',
|
||||
],
|
||||
'demo': [
|
||||
'demo/document_page.xml'
|
||||
|
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<template id="document_page_css">
|
||||
<link rel="stylesheet" type="text/less" href="/document_page/static/src/css/document_page.css"/>
|
||||
</template>
|
||||
</odoo>
|
@ -9,7 +9,7 @@
|
||||
<record id="demo_category1" model="document.page">
|
||||
<field name="name">OpenERP Features</field>
|
||||
<field name="type">category</field>
|
||||
<field name="content">
|
||||
<field name="template">
|
||||
Summary of the feature
|
||||
|
||||
Long explanation
|
||||
|
12
document_page/migrations/10.0.2.0.0/post-migration.py
Normal file
12
document_page/migrations/10.0.2.0.0/post-migration.py
Normal file
@ -0,0 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2018 Ivan Todorovich <ivan.todorovich@gmail.com>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
|
||||
def migrate(cr, version): # pragma: no cover
|
||||
# Set all pre-existing categories template to its content
|
||||
cr.execute("""
|
||||
UPDATE document_page
|
||||
SET template = content
|
||||
WHERE type = 'category'
|
||||
""")
|
@ -2,11 +2,8 @@
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
import logging
|
||||
from odoo import api, fields, models
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DocumentPage(models.Model):
|
||||
"""This class is use to manage Document."""
|
||||
@ -37,17 +34,48 @@ class DocumentPage(models.Model):
|
||||
'Children'
|
||||
)
|
||||
|
||||
content = fields.Text("Content")
|
||||
content = fields.Text(
|
||||
"Content",
|
||||
compute='_compute_content',
|
||||
inverse='_inverse_content',
|
||||
search='_search_content',
|
||||
required=True,
|
||||
)
|
||||
|
||||
# no-op computed field
|
||||
summary = fields.Char(
|
||||
help='Describe the changes made',
|
||||
compute=lambda x: x,
|
||||
inverse=lambda x: x,
|
||||
)
|
||||
|
||||
template = fields.Html(
|
||||
"Template",
|
||||
help="Template that will be used as a content template "
|
||||
"for all new page of this category.",
|
||||
)
|
||||
|
||||
# deprecated - should be removed on 11.0
|
||||
# left here because some modules might still need it
|
||||
display_content = fields.Text(
|
||||
string='Displayed Content',
|
||||
compute='_get_display_content'
|
||||
compute='_compute_display_content'
|
||||
)
|
||||
|
||||
history_head = fields.Many2one(
|
||||
'document.page.history',
|
||||
'HEAD',
|
||||
compute='_compute_history_head',
|
||||
store=True,
|
||||
auto_join=True,
|
||||
)
|
||||
|
||||
history_ids = fields.One2many(
|
||||
'document.page.history',
|
||||
'page_id',
|
||||
'History'
|
||||
'History',
|
||||
order='create_date DESC',
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
menu_id = fields.Many2one(
|
||||
@ -56,82 +84,88 @@ class DocumentPage(models.Model):
|
||||
readonly=True
|
||||
)
|
||||
|
||||
create_date = fields.Datetime(
|
||||
"Created on",
|
||||
readonly=True
|
||||
content_date = fields.Datetime(
|
||||
'Last Contribution Date',
|
||||
related='history_head.create_date',
|
||||
store=True,
|
||||
index=True,
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
create_uid = fields.Many2one(
|
||||
content_uid = fields.Many2one(
|
||||
'res.users',
|
||||
'Author',
|
||||
readonly=True
|
||||
'Last Contributor',
|
||||
related='history_head.create_uid',
|
||||
store=True,
|
||||
index=True,
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
write_date = fields.Datetime(
|
||||
"Modification Date",
|
||||
readonly=True
|
||||
)
|
||||
|
||||
write_uid = fields.Many2one(
|
||||
'res.users',
|
||||
"Last Contributor",
|
||||
readonly=True
|
||||
)
|
||||
|
||||
def _get_page_index(self, page, link=True):
|
||||
@api.multi
|
||||
def _get_page_index(self, link=True):
|
||||
"""Return the index of a document."""
|
||||
self.ensure_one()
|
||||
index = []
|
||||
for subpage in page.child_ids:
|
||||
index += ["<li>" + self._get_page_index(subpage) +
|
||||
"</li>"]
|
||||
for subpage in self.child_ids:
|
||||
index += ["<li>" + subpage._get_page_index() + "</li>"]
|
||||
r = ''
|
||||
if link:
|
||||
r = '<a href="#id=%s">%s</a>' % (page.id, page.name)
|
||||
r = '<a href="#id=%s">%s</a>' % (self.id, self.name)
|
||||
|
||||
if index:
|
||||
r += "<ul>" + "".join(index) + "</ul>"
|
||||
return r
|
||||
|
||||
def _get_display_content(self):
|
||||
"""Return the content of a document."""
|
||||
for page in self:
|
||||
if page.type == "category":
|
||||
display_content = self._get_page_index(page, link=False)
|
||||
@api.multi
|
||||
@api.depends('content')
|
||||
def _compute_display_content(self):
|
||||
# @deprecated, simply use content
|
||||
for rec in self:
|
||||
rec.display_content = rec.content
|
||||
|
||||
@api.multi
|
||||
@api.depends('history_head', 'history_ids')
|
||||
def _compute_content(self):
|
||||
for rec in self:
|
||||
if rec.type == 'category':
|
||||
rec.content = rec._get_page_index(link=False)
|
||||
else:
|
||||
display_content = page.content
|
||||
page.display_content = display_content
|
||||
if rec.history_head:
|
||||
rec.content = rec.history_head.content
|
||||
else:
|
||||
# html widget's default, so it doesn't trigger ghost save
|
||||
rec.content = '<p><br></p>'
|
||||
|
||||
@api.onchange("parent_id")
|
||||
def do_set_content(self):
|
||||
"""We Set it the right content to the new parent."""
|
||||
if self.parent_id and not self.content:
|
||||
if self.parent_id.type == "category":
|
||||
self.content = self.parent_id.content
|
||||
|
||||
def create_history(self, page_id, content):
|
||||
"""Create the first history of a newly created document."""
|
||||
history = self.env['document.page.history']
|
||||
return history.create({
|
||||
"content": content,
|
||||
"page_id": page_id
|
||||
@api.multi
|
||||
def _inverse_content(self):
|
||||
for rec in self:
|
||||
if rec.type == 'content':
|
||||
rec._create_history({
|
||||
'content': rec.content,
|
||||
'summary': rec.summary,
|
||||
})
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
"""Write the content and set the history."""
|
||||
result = super(DocumentPage, self).write(vals)
|
||||
content = vals.get('content')
|
||||
if content:
|
||||
for page in self:
|
||||
self.create_history(page.id, content)
|
||||
return result
|
||||
def _search_content(self, operator, value):
|
||||
return [('history_head.content', operator, value)]
|
||||
|
||||
@api.model
|
||||
@api.returns('self', lambda value: value.id)
|
||||
def create(self, vals):
|
||||
"""Create the first history of a document."""
|
||||
page_id = super(DocumentPage, self).create(vals)
|
||||
content = vals.get('content')
|
||||
if content:
|
||||
self.create_history(page_id.id, content)
|
||||
return page_id
|
||||
@api.multi
|
||||
@api.depends('history_ids')
|
||||
def _compute_history_head(self):
|
||||
for rec in self:
|
||||
if rec.history_ids:
|
||||
rec.history_head = rec.history_ids[0]
|
||||
|
||||
@api.multi
|
||||
def _create_history(self, vals):
|
||||
self.ensure_one()
|
||||
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 == '<p><br></p>':
|
||||
if self.parent_id and self.parent_id.type == "category":
|
||||
self.content = self.parent_id.template
|
||||
|
@ -2,13 +2,10 @@
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
import logging
|
||||
import difflib
|
||||
from odoo import fields, models
|
||||
from odoo import api, fields, models
|
||||
from odoo.tools.translate import _
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DocumentPageHistory(models.Model):
|
||||
"""This model is necessary to manage a document history."""
|
||||
@ -16,24 +13,40 @@ class DocumentPageHistory(models.Model):
|
||||
_name = "document.page.history"
|
||||
_description = "Document Page History"
|
||||
_order = 'id DESC'
|
||||
_rec_name = "create_date"
|
||||
|
||||
page_id = fields.Many2one('document.page', 'Page')
|
||||
page_id = fields.Many2one('document.page', 'Page', ondelete='cascade')
|
||||
summary = fields.Char('Summary', index=True)
|
||||
content = fields.Text("Content")
|
||||
create_date = fields.Datetime("Date")
|
||||
create_uid = fields.Many2one('res.users', "Modified By")
|
||||
diff = fields.Text(compute='_compute_diff')
|
||||
|
||||
@api.multi
|
||||
@api.depends('content', 'page_id.history_ids')
|
||||
def _compute_diff(self):
|
||||
"""Shows a diff between this version and the previous version"""
|
||||
history = self.env['document.page.history']
|
||||
for rec in self:
|
||||
prev = history.search([
|
||||
('page_id', '=', rec.page_id.id),
|
||||
('create_date', '<', rec.create_date)],
|
||||
limit=1,
|
||||
order='create_date DESC')
|
||||
if prev:
|
||||
rec.diff = self.getDiff(prev.id, rec.id)
|
||||
else:
|
||||
rec.diff = self.getDiff(False, rec.id)
|
||||
|
||||
@api.model
|
||||
def getDiff(self, v1, v2):
|
||||
"""Return the difference between two version of document version."""
|
||||
text1 = self.browse(v1).content
|
||||
text2 = self.browse(v2).content
|
||||
line1 = line2 = ''
|
||||
if text1:
|
||||
text1 = v1 and self.browse(v1).content or ''
|
||||
text2 = v2 and self.browse(v2).content or ''
|
||||
# Include line breaks to make it more readable
|
||||
# TODO: consider using a beautify library directly on the content
|
||||
text1 = text1.replace('</p><p>', '</p>\r\n<p>')
|
||||
text2 = text2.replace('</p><p>', '</p>\r\n<p>')
|
||||
line1 = text1.splitlines(1)
|
||||
if text2:
|
||||
line2 = text2.splitlines(1)
|
||||
if (not line1 and not line2) or (line1 == line2):
|
||||
if line1 == line2:
|
||||
return _('There are no changes in revisions.')
|
||||
else:
|
||||
diff = difflib.HtmlDiff()
|
||||
@ -43,3 +56,11 @@ class DocumentPageHistory(models.Model):
|
||||
"Revision-{}".format(v2),
|
||||
context=True
|
||||
)
|
||||
|
||||
@api.multi
|
||||
def name_get(self):
|
||||
result = []
|
||||
for rec in self:
|
||||
name = "%s #%i" % (rec.page_id.name, rec.id)
|
||||
result.append((rec.id, name))
|
||||
return result
|
||||
|
@ -1,7 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="knowledge.group_document_user" model="res.groups">
|
||||
<record id="group_document_editor" model="res.groups">
|
||||
<field name="name">Editor</field>
|
||||
<field name="category_id" ref="knowledge.module_category_knowledge"/>
|
||||
<field name="implied_ids" eval="[(4, ref('knowledge.group_document_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="group_document_manager" model="res.groups">
|
||||
<field name="name">Manager</field>
|
||||
<field name="category_id" ref="knowledge.module_category_knowledge"/>
|
||||
<field name="implied_ids" eval="[(4, ref('group_document_editor'))]"/>
|
||||
<field name="users" eval="[(4, ref('base.user_root'))]"/>
|
||||
</record>
|
||||
|
||||
|
@ -1,4 +1,7 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
document_page_all,document.page,model_document_page,,1,0,0,0
|
||||
document_page,document.page,model_document_page,base.group_user,1,1,1,1
|
||||
document_page_history,document.page.history,model_document_page_history,base.group_user,1,0,1,0
|
||||
document_page_user,document.page user,model_document_page,knowledge.group_document_user,1,0,0,0
|
||||
document_page_history_user,document.page.history user,model_document_page_history,knowledge.group_document_user,1,0,0,0
|
||||
document_page_editor,document.page editor,model_document_page,group_document_editor,1,1,1,0
|
||||
document_page_history_editor,document.page.history editor,model_document_page_history,group_document_editor,1,1,1,0
|
||||
document_page_manager,document.page manager,model_document_page,group_document_manager,1,1,1,1
|
||||
document_page_history_manager,document.page.history manager,model_document_page_history,group_document_manager,1,1,1,0
|
||||
|
|
@ -1,12 +1,29 @@
|
||||
.oe_form_editable .oe_document_page {
|
||||
display: none;
|
||||
table.diff {
|
||||
font-family: Courier;
|
||||
border: medium;
|
||||
}
|
||||
|
||||
table.diff {font-family:Courier; border:medium;}
|
||||
.diff_header {background-color:#e0e0e0}
|
||||
td.diff_header {text-align:right}
|
||||
.diff_next {background-color:#c0c0c0}
|
||||
.diff_add {background-color:#aaffaa}
|
||||
.diff_chg {background-color:#ffff77}
|
||||
.diff_sub {background-color:#ffaaaa}
|
||||
table.diff .diff_header {
|
||||
background-color: #e0e0e0
|
||||
}
|
||||
|
||||
table.diff td.diff_header {
|
||||
text-align: right
|
||||
}
|
||||
|
||||
table.diff .diff_next {
|
||||
background-color:#c0c0c0
|
||||
}
|
||||
|
||||
table.diff .diff_add {
|
||||
background-color:#aaffaa
|
||||
}
|
||||
|
||||
table.diff .diff_chg {
|
||||
background-color:#ffff77
|
||||
}
|
||||
|
||||
table.diff .diff_sub {
|
||||
background-color:#ffaaaa
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import test_document_page, test_document_page_history
|
||||
from . import test_document_page
|
||||
from . import test_document_page_create_menu
|
||||
from . import test_document_page_show_diff
|
||||
|
@ -4,34 +4,37 @@ from odoo.tests import common
|
||||
|
||||
|
||||
class TestDocumentPage(common.TransactionCase):
|
||||
"""document_page test class."""
|
||||
|
||||
def setUp(self):
|
||||
super(TestDocumentPage, self).setUp()
|
||||
self.page_obj = self.env['document.page']
|
||||
self.history_obj = self.env['document.page.history']
|
||||
self.category1 = self.env.ref('document_page.demo_category1')
|
||||
self.page1 = self.env.ref('document_page.demo_page1')
|
||||
|
||||
def test_page_creation(self):
|
||||
"""Test page creation."""
|
||||
parent_page = self.env.ref('document_page.demo_category1')
|
||||
|
||||
self.assertEqual(parent_page.name, 'OpenERP Features')
|
||||
|
||||
record = self.env['document.page'].create({
|
||||
page = self.page_obj.create({
|
||||
'name': 'Test Page 1',
|
||||
'parent_id': parent_page.id,
|
||||
'parent_id': self.category1.id,
|
||||
'content': 'Test content'
|
||||
})
|
||||
self.assertEqual(record.name, 'Test Page1')
|
||||
self.assertEqual(page.content, 'Test content')
|
||||
self.assertEqual(len(page.history_ids), 1)
|
||||
page.content = 'New content for Demo Page'
|
||||
self.assertEqual(len(page.history_ids), 2)
|
||||
|
||||
def test_category_display_content(self):
|
||||
"""Test category display content."""
|
||||
page = self.env.ref('document_page.demo_category1')
|
||||
self.assertTrue(page.display_content.find('Demo') > 1)
|
||||
def test_category_template(self):
|
||||
page = self.page_obj.create({
|
||||
'name': 'Test Page 2',
|
||||
'parent_id': self.category1.id,
|
||||
})
|
||||
page._onchange_parent_id()
|
||||
self.assertEqual(page.content, self.category1.template)
|
||||
|
||||
def test_page_display_content(self):
|
||||
"""Test page display content."""
|
||||
page = self.env.ref('document_page.demo_page1')
|
||||
self.assertTrue(page.display_content.find('Demo') > 1)
|
||||
|
||||
def test_page_do_set_content(self):
|
||||
"""Test page set content."""
|
||||
page = self.env.ref('document_page.demo_page1')
|
||||
page.content = None
|
||||
page.do_set_content()
|
||||
self.assertTrue(page.display_content.find('Summary') == 1)
|
||||
def test_page_history_diff(self):
|
||||
page = self.page_obj.create({
|
||||
'name': 'Test Page 3',
|
||||
'content': 'Test content'
|
||||
})
|
||||
page.content = 'New content'
|
||||
self.assertIsNotNone(page.history_ids[0].diff)
|
||||
|
@ -8,7 +8,7 @@ class TestDocumentPageCreateMenu(common.TransactionCase):
|
||||
|
||||
def test_page_menu_creation(self):
|
||||
"""Test page menu creation."""
|
||||
menu_parent = self.env.ref('knowledge.menu_document_root')
|
||||
menu_parent = self.env.ref('knowledge.menu_document')
|
||||
|
||||
menu_created = self.env['document.page.create.menu'].create(
|
||||
{'menu_name': 'Wiki Test menu', 'menu_parent_id': menu_parent.id}
|
||||
|
@ -19,7 +19,7 @@ class TestDocumentPageShowDiff(common.TransactionCase):
|
||||
self.assertTrue(
|
||||
show_diff_object.with_context(
|
||||
active_ids=[i.id for i in history_pages]
|
||||
).get_diff()
|
||||
)._get_diff()
|
||||
)
|
||||
|
||||
page.write({'content': 'Text content updated'})
|
||||
@ -30,7 +30,7 @@ class TestDocumentPageShowDiff(common.TransactionCase):
|
||||
with self.assertRaises(Exception) as context:
|
||||
show_diff_object.with_context(
|
||||
active_ids=[i.id for i in history_pages]
|
||||
).get_diff()
|
||||
)._get_diff()
|
||||
|
||||
self.assertTrue(_("Select one or maximum two history revisions!")
|
||||
in context.exception)
|
||||
|
@ -1,11 +1,6 @@
|
||||
<?xml version="1.0"?>
|
||||
<odoo>
|
||||
|
||||
<menuitem name="Pages"
|
||||
id="menu_wiki"
|
||||
parent="knowledge.menu_document"
|
||||
sequence="20" />
|
||||
|
||||
<!-- wiki tree view -->
|
||||
<record id="view_wiki_tree_children" model="ir.ui.view">
|
||||
<field name="name">document.page.tree</field>
|
||||
@ -15,8 +10,8 @@
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Document Page">
|
||||
<field name="name"/>
|
||||
<field name="write_uid"/>
|
||||
<field name="write_date"/>
|
||||
<field name="content_uid"/>
|
||||
<field name="content_date"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@ -30,8 +25,8 @@
|
||||
<field name="name"/>
|
||||
<field name="parent_id"/>
|
||||
<field name="create_uid" invisible="1"/>
|
||||
<field name="write_uid"/>
|
||||
<field name="write_date"/>
|
||||
<field name="content_uid"/>
|
||||
<field name="content_date"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@ -47,31 +42,32 @@
|
||||
<h1><field name="name" placeholder="Name"/></h1>
|
||||
<group>
|
||||
<group>
|
||||
<field name="parent_id"
|
||||
string="Category"
|
||||
context="{'default_type':'category'}"/>
|
||||
<field name="parent_id" string="Category" context="{'default_type':'category'}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="write_uid"
|
||||
groups="base.group_no_one"/>
|
||||
<field name="write_date"
|
||||
groups="base.group_no_one"/>
|
||||
<field name="menu_id"
|
||||
groups="base.group_no_one"/>
|
||||
<field name="content_uid"/>
|
||||
<field name="content_date"/>
|
||||
<field name="menu_id" readonly="1" attrs="{'invisible': [('menu_id','=',False)]}"/>
|
||||
</group>
|
||||
</group>
|
||||
<separator string="Content" class="oe_edit_only" />
|
||||
<field name="content"
|
||||
placeholder="e.g. Once upon a time..."
|
||||
class="oe_edit_only"
|
||||
widget="html" />
|
||||
<separator string="Last Content" />
|
||||
<div class="oe_document_page">
|
||||
<field name="display_content"
|
||||
widget="html"
|
||||
class="oe_view_only"
|
||||
options='{"safe": True}' />
|
||||
</div>
|
||||
<notebook>
|
||||
<page name="content" string="Content">
|
||||
<label for="summary" class="oe_edit_only" />
|
||||
<field name="summary" placeholder="eg: Changed ... for ..." class="oe_edit_only" />
|
||||
<label for="content" class="oe_edit_only"/>
|
||||
<field name="content" widget="html" placeholder="e.g. Once upon a time..." required="1" options="{'safe': True}"/>
|
||||
</page>
|
||||
<page name="history" string="History">
|
||||
<field name="history_ids">
|
||||
<tree>
|
||||
<field name="id"/>
|
||||
<field name="create_date"/>
|
||||
<field name="summary"/>
|
||||
<field name="create_uid"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
@ -88,12 +84,7 @@
|
||||
<form string="Document Page">
|
||||
<field name="type" invisible="1"/>
|
||||
<h1><field name="name" placeholder="Name"/></h1>
|
||||
<div class="oe_document_page">
|
||||
<field name="display_content"
|
||||
widget="html"
|
||||
class="oe_view_only"
|
||||
options='{"safe": True}' />
|
||||
</div>
|
||||
<field name="content" class="oe_view_only" required="1" options='{"safe": True}'/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
@ -104,90 +95,19 @@
|
||||
<field name="model">document.page</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Document Page">
|
||||
<field name="name"
|
||||
string="Content"
|
||||
filter_domain="['|', ('name','ilike',self), ('content','ilike',self)]"/>
|
||||
<field name="write_uid"/>
|
||||
<field name="name" string="Content" filter_domain="['|', ('name','ilike',self), ('content','ilike',self)]"/>
|
||||
<field name="parent_id"/>
|
||||
<field name="create_uid"/>
|
||||
<field name="content_uid"/>
|
||||
<group expand="0" string="Group By...">
|
||||
<filter string="Document Type"
|
||||
domain="[]"
|
||||
context="{'group_by':'parent_id'}" />
|
||||
<filter string="Author"
|
||||
domain="[]"
|
||||
context="{'group_by':'create_uid'}" />
|
||||
<filter string="Last Contributor"
|
||||
domain="[]"
|
||||
context="{'group_by':'write_uid'}" />
|
||||
<filter string="Category" context="{'group_by':'parent_id'}" />
|
||||
<filter string="Author" context="{'group_by':'create_uid'}" />
|
||||
<filter string="Last Contributor" context="{'group_by':'content_uid'}" />
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Category Views -->
|
||||
<record id="view_category_form" model="ir.ui.view">
|
||||
<field name="name">document.page.category.form</field>
|
||||
<field name="model">document.page</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Category">
|
||||
<sheet>
|
||||
<field name="type" invisible="1"/>
|
||||
<h1><field name="name" placeholder="Name"/></h1>
|
||||
<group>
|
||||
<group>
|
||||
<field name="parent_id" string="Category"
|
||||
context="{'default_type':'category'}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="write_uid"
|
||||
groups="base.group_no_one"/>
|
||||
<field name="write_date"
|
||||
groups="base.group_no_one"/>
|
||||
<field name="menu_id"
|
||||
groups="base.group_no_one"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Template" name="template">
|
||||
<div>
|
||||
<label for="content"
|
||||
string="Template that will be used as a content template for all new page of this category."/>
|
||||
</div>
|
||||
<field name="content"
|
||||
placeholder="e.g. Once upon a time..."
|
||||
widget="html" />
|
||||
</page>
|
||||
<page string="Documents" name="documents">
|
||||
<div class="oe_document_page">
|
||||
<field name="display_content"
|
||||
widget="html"
|
||||
class="oe_view_only"
|
||||
options='{"safe": True}' />
|
||||
</div>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_category_tree" model="ir.ui.view">
|
||||
<field name="name">document.page.category.tree</field>
|
||||
<field name="model">document.page</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Categories">
|
||||
<field name="name"/>
|
||||
<field name="parent_id"/>
|
||||
<field name="create_uid" invisible="1"/>
|
||||
<field name="write_uid"/>
|
||||
<field name="write_date"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- page action -->
|
||||
<record id="action_page" model="ir.actions.act_window">
|
||||
@ -205,103 +125,35 @@
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_page_view_tree" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="0" />
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="view_id" ref="view_wiki_tree"/>
|
||||
<field name="act_window_id" ref="action_page"/>
|
||||
</record>
|
||||
|
||||
<record id="action_page_view_form" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="5" />
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="view_wiki_form"/>
|
||||
<field name="act_window_id" ref="action_page"/>
|
||||
</record>
|
||||
<menuitem id="menu_page"
|
||||
parent="menu_wiki"
|
||||
|
||||
|
||||
|
||||
<menuitem id="menu_wiki"
|
||||
name="Pages"
|
||||
parent="knowledge.menu_document"
|
||||
sequence="20" />
|
||||
|
||||
|
||||
<menuitem id="menu_page"
|
||||
name="Pages"
|
||||
parent="menu_wiki"
|
||||
action="action_page"
|
||||
sequence="10" />
|
||||
|
||||
<record id="action_category" model="ir.actions.act_window">
|
||||
<field name="name">Category</field>
|
||||
<field name="res_model">document.page</field>
|
||||
<field name="domain">[('type','=','category')]</field>
|
||||
<field name="context">{'default_type': 'category'}</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_category_tree"/>
|
||||
<field name="search_view_id" ref="view_wiki_filter"/>
|
||||
</record>
|
||||
<record id="action_category_view_tree" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="0" />
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="view_id" ref="view_category_tree"/>
|
||||
<field name="act_window_id" ref="action_category"/>
|
||||
</record>
|
||||
<record id="action_category_view_form" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="5" />
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="view_category_form"/>
|
||||
<field name="act_window_id" ref="action_category"/>
|
||||
</record>
|
||||
<menuitem id="menu_category"
|
||||
parent="menu_wiki"
|
||||
name="Categories"
|
||||
action="action_category"
|
||||
sequence="20"/>
|
||||
|
||||
<!-- History Tree view -->
|
||||
<record model="ir.ui.view" id="view_wiki_history_tree">
|
||||
<field name="name">document.page.history.tree</field>
|
||||
<field name="model">document.page.history</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Document History">
|
||||
<field name="create_date"/>
|
||||
<field name="create_uid"/>
|
||||
<field name="page_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<!-- History Form view -->
|
||||
<record model="ir.ui.view" id="wiki_history_form">
|
||||
<field name="name">document.page.history.form</field>
|
||||
<field name="model">document.page.history</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Document Page History" version="7.0">
|
||||
<label for="page_id" class="oe_edit_only"/>
|
||||
<h1><field name="page_id" select="1" /></h1>
|
||||
<label for="create_date" class="oe_edit_only"/>
|
||||
<field name="create_date" readonly="1"/>
|
||||
<label for="content" class="oe_edit_only"/>
|
||||
<field name="content" colspan="4"
|
||||
widget="html" options='{"safe": True}'/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- History Action -->
|
||||
<record model="ir.actions.act_window" id="action_history">
|
||||
<field name="name">Page history</field>
|
||||
<field name="res_model">document.page.history</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_page_history"
|
||||
parent="menu_wiki"
|
||||
name="Pages history"
|
||||
action="action_history"
|
||||
sequence="30"
|
||||
groups="base.group_no_one" />
|
||||
|
||||
<act_window
|
||||
id="action_related_page_history"
|
||||
context="{'search_default_page_id': [active_id], 'default_page_id': active_id}"
|
||||
domain="[('page_id','=',active_id)]"
|
||||
name="Page History"
|
||||
res_model="document.page.history"
|
||||
src_model="document.page"/>
|
||||
|
||||
<act_window
|
||||
id="action_related_page_create_menu"
|
||||
|
10
document_page/views/document_page_assets.xml
Normal file
10
document_page/views/document_page_assets.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
|
||||
<template id="assets_backend" name="document_page assets" inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<link rel="stylesheet" href="/document_page/static/src/css/document_page.css"/>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
</odoo>
|
88
document_page/views/document_page_category.xml
Executable file
88
document_page/views/document_page_category.xml
Executable file
@ -0,0 +1,88 @@
|
||||
<?xml version="1.0"?>
|
||||
<odoo>
|
||||
|
||||
<!-- Category Views -->
|
||||
<record id="view_category_form" model="ir.ui.view">
|
||||
<field name="name">document.page.category.form</field>
|
||||
<field name="model">document.page</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Category">
|
||||
<sheet>
|
||||
<field name="type" invisible="1"/>
|
||||
<h1><field name="name" placeholder="Name"/></h1>
|
||||
<group>
|
||||
<group>
|
||||
<field name="parent_id" string="Category" context="{'default_type':'category'}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="write_uid" groups="base.group_no_one"/>
|
||||
<field name="write_date" groups="base.group_no_one"/>
|
||||
<field name="menu_id" groups="base.group_no_one"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Template" name="template">
|
||||
<field name="template" placeholder="e.g. Once upon a time..." />
|
||||
</page>
|
||||
<page string="Documents" name="documents">
|
||||
<field name="content" widget="html" class="oe_view_only" options='{"safe": True}' />
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_category_tree" model="ir.ui.view">
|
||||
<field name="name">document.page.category.tree</field>
|
||||
<field name="model">document.page</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Categories">
|
||||
<field name="name"/>
|
||||
<field name="parent_id"/>
|
||||
<field name="create_uid" invisible="1"/>
|
||||
<field name="write_uid"/>
|
||||
<field name="write_date"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- Category Action -->
|
||||
<record id="action_category" model="ir.actions.act_window">
|
||||
<field name="name">Category</field>
|
||||
<field name="res_model">document.page</field>
|
||||
<field name="domain">[('type','=','category')]</field>
|
||||
<field name="context">{'default_type': 'category'}</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_category_tree"/>
|
||||
<field name="search_view_id" ref="view_wiki_filter"/>
|
||||
</record>
|
||||
|
||||
<record id="action_category_view_tree" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="0" />
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="view_id" ref="view_category_tree"/>
|
||||
<field name="act_window_id" ref="action_category"/>
|
||||
</record>
|
||||
|
||||
<record id="action_category_view_form" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="5" />
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="view_category_form"/>
|
||||
<field name="act_window_id" ref="action_category"/>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_category"
|
||||
parent="menu_wiki"
|
||||
name="Categories"
|
||||
action="action_category"
|
||||
sequence="20"/>
|
||||
|
||||
|
||||
</odoo>
|
88
document_page/views/document_page_history.xml
Executable file
88
document_page/views/document_page_history.xml
Executable file
@ -0,0 +1,88 @@
|
||||
<?xml version="1.0"?>
|
||||
<odoo>
|
||||
|
||||
<!-- History Tree view -->
|
||||
<record model="ir.ui.view" id="view_wiki_history_tree">
|
||||
<field name="name">document.page.history.tree</field>
|
||||
<field name="model">document.page.history</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Document History">
|
||||
<field name="id"/>
|
||||
<field name="page_id"/>
|
||||
<field name="summary"/>
|
||||
<field name="create_uid"/>
|
||||
<field name="create_date"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- History Search view -->
|
||||
<record id="view_wiki_history_filter" model="ir.ui.view">
|
||||
<field name="name">document.page.history.search</field>
|
||||
<field name="model">document.page.history</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Document Page History">
|
||||
<field name="page_id"/>
|
||||
<field name="content"/>
|
||||
<field name="create_uid"/>
|
||||
<group expand="0" string="Group By...">
|
||||
<filter name="group_author" string="Author" context="{'group_by':'create_uid'}" />
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- History Form view -->
|
||||
<record model="ir.ui.view" id="wiki_history_form">
|
||||
<field name="name">document.page.history.form</field>
|
||||
<field name="model">document.page.history</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Document Page History">
|
||||
<sheet>
|
||||
<h1><field name="page_id"/></h1>
|
||||
<group>
|
||||
<group>
|
||||
<field name="create_uid" readonly="1"/>
|
||||
<field name="create_date" readonly="1"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page name="content" string="Content">
|
||||
<label for="summary"/>
|
||||
<field name="summary" placeholder="eg: Changed ... for ..."/>
|
||||
<label for="content"/>
|
||||
<field name="content" widget="html" placeholder="e.g. Once upon a time..." options="{'safe': True}"/>
|
||||
</page>
|
||||
<page name="diff" string="Changes">
|
||||
<field name="diff" widget="html" style="overflow-x: scroll" />
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- History Action -->
|
||||
<record model="ir.actions.act_window" id="action_history">
|
||||
<field name="name">Page history</field>
|
||||
<field name="res_model">document.page.history</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_page_history"
|
||||
parent="menu_wiki"
|
||||
name="Pages history"
|
||||
action="action_history"
|
||||
sequence="30"
|
||||
groups="base.group_no_one" />
|
||||
|
||||
<act_window id="action_related_page_history"
|
||||
context="{'search_default_page_id': [active_id], 'default_page_id': active_id}"
|
||||
domain="[('page_id','=',active_id)]"
|
||||
name="Page History"
|
||||
res_model="document.page.history"
|
||||
src_model="document.page"/>
|
||||
|
||||
|
||||
</odoo>
|
31
document_page/views/report_document_page.xml
Executable file
31
document_page/views/report_document_page.xml
Executable file
@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<template id="report_documentpage_doc">
|
||||
<t t-call="report.external_layout">
|
||||
|
||||
<div class="page">
|
||||
<h1 t-field="doc.display_name" />
|
||||
<div t-raw="doc.display_content" />
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="report_documentpage">
|
||||
<t t-call="report.html_container">
|
||||
<t t-foreach="docs" t-as="doc">
|
||||
<t t-call="document_page.report_documentpage_doc" />
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<report
|
||||
id="report_document_page"
|
||||
string="Document Page"
|
||||
model="document.page"
|
||||
report_type="qweb-pdf"
|
||||
file="document_page.report_documentpage"
|
||||
name="document_page.report_documentpage"
|
||||
/>
|
||||
|
||||
</odoo>
|
@ -2,7 +2,8 @@
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import exceptions, fields, models
|
||||
from odoo import fields, models
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tools.translate import _
|
||||
|
||||
|
||||
@ -11,33 +12,24 @@ class DocumentPageShowDiff(models.TransientModel):
|
||||
|
||||
_name = 'wizard.document.page.history.show_diff'
|
||||
|
||||
def get_diff(self):
|
||||
def _get_diff(self):
|
||||
"""Return the Difference between two document."""
|
||||
history = self.env["document.page.history"]
|
||||
ids = self.env.context.get('active_ids', [])
|
||||
|
||||
diff = ""
|
||||
diff = False
|
||||
if len(ids) == 2:
|
||||
if ids[0] > ids[1]:
|
||||
diff = history.getDiff(ids[1], ids[0])
|
||||
else:
|
||||
diff = history.getDiff(ids[0], ids[1])
|
||||
elif len(ids) == 1:
|
||||
old = history.browse(ids[0])
|
||||
nids = history.search(
|
||||
[('page_id', '=', old.page_id.id)],
|
||||
order='id DESC',
|
||||
limit=1
|
||||
)
|
||||
diff = history.getDiff(ids[0], nids.id)
|
||||
diff = history.browse(ids[0]).diff
|
||||
else:
|
||||
raise exceptions.Warning(
|
||||
_("Select one or maximum two history revisions!")
|
||||
)
|
||||
raise UserError(
|
||||
_("Select one or maximum two history revisions!"))
|
||||
return diff
|
||||
|
||||
diff = fields.Text(
|
||||
'Diff',
|
||||
readonly=True,
|
||||
default=get_diff
|
||||
default=_get_diff,
|
||||
)
|
||||
|
@ -6,14 +6,10 @@
|
||||
<field name="name">Show Difference</field>
|
||||
<field name="model">wizard.document.page.history.show_diff</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<field name="diff"
|
||||
widget="html"
|
||||
options='{"safe": True}' />
|
||||
<form string="Difference" version="7.0">
|
||||
<field name="diff" widget="html" class="overflow-x: scroll" />
|
||||
<footer>
|
||||
<button string="Close"
|
||||
class="oe_link"
|
||||
special="cancel" />
|
||||
<button string="Close" class="oe_link" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
|
Loading…
Reference in New Issue
Block a user