changeset 45787f01dc3e in trytond:default
details: https://hg.tryton.org/trytond?cmd=changeset;node=45787f01dc3e
description:
Add link button
issue9051
review280841002
diffstat:
CHANGELOG | 1 +
doc/topics/views/index.rst | 18 ++++++++++++
trytond/ir/ui/board.rnc | 12 ++++++++
trytond/ir/ui/board.rng | 61 +++++++++++++++++++++++++++++++++++++++++
trytond/ir/ui/form.rnc | 11 +++++++
trytond/ir/ui/form.rng | 60 ++++++++++++++++++++++++++++++++++++++++
trytond/model/modelview.py | 16 ++++++++++
trytond/tests/modelview.py | 12 ++++++++
trytond/tests/modelview.xml | 17 +++++++++++
trytond/tests/test_modelview.py | 35 +++++++++++++++++++++++
10 files changed, 243 insertions(+), 0 deletions(-)
diffs (480 lines):
diff -r 38b32161f535 -r 45787f01dc3e CHANGELOG
--- a/CHANGELOG Sun Apr 12 23:53:02 2020 +0200
+++ b/CHANGELOG Mon Apr 13 12:21:55 2020 +0200
@@ -1,3 +1,4 @@
+* Add link button on form
* Support explicit delete and remove for saving and on_change xxx2Many
* Add export_data_domain to ModelStorage
* Add route to export CSV data
diff -r 38b32161f535 -r 45787f01dc3e doc/topics/views/index.rst
--- a/doc/topics/views/index.rst Sun Apr 12 23:53:02 2020 +0200
+++ b/doc/topics/views/index.rst Mon Apr 13 12:21:55 2020 +0200
@@ -384,6 +384,24 @@
value of the ``string``, ``confirm`` and ``help`` attributes can be can be
defined.
+.. _form-link:
+
+link
+^^^^
+
+Display an `ir.action.act_window` as a button with a counter or one counter per
+tab. When clicked it opens the window.
+
+ * ``name``: The XML id of `ir.action.act_window`.
+
+ * ``colspan``: see in common-attributes-colspan_.
+
+ * ``states``: see in common-attributes-states_.
+
+ * ``icon``: The name of the icon to display.
+
+ * ``empty``: If set to `hide` the button is not displayed if the counter is
+ zero. The default is ``show``.
notebook
^^^^^^^^
diff -r 38b32161f535 -r 45787f01dc3e trytond/ir/ui/board.rnc
--- a/trytond/ir/ui/board.rnc Sun Apr 12 23:53:02 2020 +0200
+++ b/trytond/ir/ui/board.rnc Mon Apr 13 12:21:55 2020 +0200
@@ -7,6 +7,7 @@
| separator
| label
| newline
+ | link
| notebook
| group
| hpaned
@@ -58,6 +59,13 @@
attlist.label &= attribute help { text }?
newline = element newline { attlist.newline, empty }
attlist.newline &= attribute id { text }
+link = element link { attlist.link, empty }
+attlist.link &= attribute name { text }
+attlist.link &= attribute id { text }?
+attlist.link &= [ a:defaultValue = "1" ] attribute colspan { text }?
+attlist.link &= attribute states { text }?
+attlist.link &= attribute icon { text }?
+attlist.link &= [ a:defaultValue = "show" ] attribute empty { "show" | "hide"
}?
notebook = element notebook { attlist.notebook, page* }
attlist.notebook &= [ a:defaultValue = "4" ] attribute colspan { text }?
page =
@@ -67,6 +75,7 @@
| separator
| label
| newline
+ | link
| notebook
| group
| hpaned
@@ -85,6 +94,7 @@
| separator
| label
| newline
+ | link
| notebook
| group
| hpaned
@@ -120,6 +130,7 @@
| separator
| label
| newline
+ | link
| notebook
| group
| hpaned
@@ -137,6 +148,7 @@
| separator
| label
| newline
+ | link
| notebook
| group
| hpaned
diff -r 38b32161f535 -r 45787f01dc3e trytond/ir/ui/board.rng
--- a/trytond/ir/ui/board.rng Sun Apr 12 23:53:02 2020 +0200
+++ b/trytond/ir/ui/board.rng Mon Apr 13 12:21:55 2020 +0200
@@ -11,6 +11,7 @@
<ref name="separator"/>
<ref name="label"/>
<ref name="newline"/>
+ <ref name="link"/>
<ref name="notebook"/>
<ref name="group"/>
<ref name="hpaned"/>
@@ -336,6 +337,62 @@
<text/>
</attribute>
</define>
+ <define name="link">
+ <element>
+ <name ns="">link</name>
+ <ref name="attlist.link"/>
+ <empty/>
+ </element>
+ </define>
+ <define name="attlist.link" combine="interleave">
+ <attribute>
+ <name ns="">name</name>
+ <text/>
+ </attribute>
+ </define>
+ <define name="attlist.link" combine="interleave">
+ <optional>
+ <attribute>
+ <name ns="">id</name>
+ <text/>
+ </attribute>
+ </optional>
+ </define>
+ <define name="attlist.link" combine="interleave">
+ <optional>
+ <attribute a:defaultValue="1">
+ <name ns="">colspan</name>
+ <text/>
+ </attribute>
+ </optional>
+ </define>
+ <define name="attlist.link" combine="interleave">
+ <optional>
+ <attribute>
+ <name ns="">states</name>
+ <text/>
+ </attribute>
+ </optional>
+ </define>
+ <define name="attlist.link" combine="interleave">
+ <optional>
+ <attribute>
+ <name ns="">icon</name>
+ <text/>
+ </attribute>
+ </optional>
+ </define>
+ <define name="attlist.link" combine="interleave">
+ <optional>
+ <attribute a:defaultValue="show">
+ <name ns="">empty</name>
+ <choice>
+ <value>show</value>
+ <value>hide</value>
+ </choice>
+ </attribute>
+ </optional>
+ </define>
<define name="notebook">
<element>
<name ns="">notebook</name>
@@ -363,6 +420,7 @@
<ref name="separator"/>
<ref name="label"/>
<ref name="newline"/>
+ <ref name="link"/>
<ref name="notebook"/>
<ref name="group"/>
<ref name="hpaned"/>
@@ -418,6 +476,7 @@
<ref name="separator"/>
<ref name="label"/>
<ref name="newline"/>
+ <ref name="link"/>
<ref name="notebook"/>
<ref name="group"/>
<ref name="hpaned"/>
@@ -575,6 +634,7 @@
<ref name="separator"/>
<ref name="label"/>
<ref name="newline"/>
+ <ref name="link"/>
<ref name="notebook"/>
<ref name="group"/>
<ref name="hpaned"/>
@@ -612,6 +672,7 @@
<ref name="separator"/>
<ref name="label"/>
<ref name="newline"/>
+ <ref name="link"/>
<ref name="notebook"/>
<ref name="group"/>
<ref name="hpaned"/>
diff -r 38b32161f535 -r 45787f01dc3e trytond/ir/ui/form.rnc
--- a/trytond/ir/ui/form.rnc Sun Apr 12 23:53:02 2020 +0200
+++ b/trytond/ir/ui/form.rnc Mon Apr 13 12:21:55 2020 +0200
@@ -9,6 +9,7 @@
| separator
| newline
| button
+ | link
| notebook
| group
| hpaned
@@ -152,6 +153,13 @@
attlist.button &= [ a:defaultValue = "0" ] attribute rule { "0" | "1" }?
attlist.button &= attribute change { text }?
attlist.button &= attribute type { "class" | "instance" }?
+link = element link { attlist.link, empty }
+attlist.link &= attribute name { text }
+attlist.link &= attribute id { text }?
+attlist.link &= [ a:defaultValue = "1" ] attribute colspan { text }?
+attlist.link &= attribute states { text }?
+attlist.link &= attribute icon { text }?
+attlist.link &= [ a:defaultValue = "show" ] attribute empty { "show" | "hide"
}?
notebook = element notebook { attlist.notebook, page* }
attlist.notebook &= [ a:defaultValue = "4" ] attribute colspan { text }?
attlist.notebook &= [ a:defaultValue = "1" ] attribute yexpand { "0" | "1" }?
@@ -189,6 +197,7 @@
| separator
| newline
| button
+ | link
| notebook
| group
| hpaned
@@ -228,6 +237,7 @@
| separator
| newline
| button
+ | link
| notebook
| group
| hpaned
@@ -246,6 +256,7 @@
| separator
| newline
| button
+ | link
| notebook
| group
| hpaned
diff -r 38b32161f535 -r 45787f01dc3e trytond/ir/ui/form.rng
--- a/trytond/ir/ui/form.rng Sun Apr 12 23:53:02 2020 +0200
+++ b/trytond/ir/ui/form.rng Mon Apr 13 12:21:55 2020 +0200
@@ -13,6 +13,7 @@
<ref name="separator"/>
<ref name="newline"/>
<ref name="button"/>
+ <ref name="link"/>
<ref name="notebook"/>
<ref name="group"/>
<ref name="hpaned"/>
@@ -780,6 +781,62 @@
</attribute>
</optional>
</define>
+ <define name="link">
+ <element>
+ <name ns="">link</name>
+ <ref name="attlist.link"/>
+ <empty/>
+ </element>
+ </define>
+ <define name="attlist.link" combine="interleave">
+ <attribute>
+ <name ns="">name</name>
+ <text/>
+ </attribute>
+ </define>
+ <define name="attlist.link" combine="interleave">
+ <optional>
+ <attribute>
+ <name ns="">id</name>
+ <text/>
+ </attribute>
+ </optional>
+ </define>
+ <define name="attlist.link" combine="interleave">
+ <optional>
+ <attribute a:defaultValue="1">
+ <name ns="">colspan</name>
+ <text/>
+ </attribute>
+ </optional>
+ </define>
+ <define name="attlist.link" combine="interleave">
+ <optional>
+ <attribute>
+ <name ns="">states</name>
+ <text/>
+ </attribute>
+ </optional>
+ </define>
+ <define name="attlist.link" combine="interleave">
+ <optional>
+ <attribute>
+ <name ns="">icon</name>
+ <text/>
+ </attribute>
+ </optional>
+ </define>
+ <define name="attlist.link" combine="interleave">
+ <optional>
+ <attribute a:defaultValue="show">
+ <name ns="">empty</name>
+ <choice>
+ <value>show</value>
+ <value>hide</value>
+ </choice>
+ </attribute>
+ </optional>
+ </define>
<define name="notebook">
<element>
<name ns="">notebook</name>
@@ -927,6 +984,7 @@
<ref name="separator"/>
<ref name="newline"/>
<ref name="button"/>
+ <ref name="link"/>
<ref name="notebook"/>
<ref name="group"/>
<ref name="hpaned"/>
@@ -1121,6 +1179,7 @@
<ref name="separator"/>
<ref name="newline"/>
<ref name="button"/>
+ <ref name="link"/>
<ref name="notebook"/>
<ref name="group"/>
<ref name="hpaned"/>
@@ -1159,6 +1218,7 @@
<ref name="separator"/>
<ref name="newline"/>
<ref name="button"/>
+ <ref name="link"/>
<ref name="notebook"/>
<ref name="group"/>
<ref name="hpaned"/>
diff -r 38b32161f535 -r 45787f01dc3e trytond/model/modelview.py
--- a/trytond/model/modelview.py Sun Apr 12 23:53:02 2020 +0200
+++ b/trytond/model/modelview.py Mon Apr 13 12:21:55 2020 +0200
@@ -526,6 +526,7 @@
ModelAccess = pool.get('ir.model.access')
Button = pool.get('ir.model.button')
User = pool.get('res.user')
+ ActionWindow = pool.get('ir.action.act_window')
if fields_width is None:
fields_width = {}
@@ -637,6 +638,21 @@
for depend in states.get('depends', []):
fields_attrs.setdefault(depend, {})
+ if element.tag == 'link':
+ link_name = element.attrib['name']
+ action_id = ModelData.get_id(*link_name.split('.'))
+ action = ActionWindow(action_id)
+ if (not action.res_model
+ or not ModelAccess.check(
+ action.res_model, 'read', raise_exception=False)):
+ element.tag = 'label'
+ colspan = element.attrib.get('colspan')
+ element.attrib.clear()
+ if colspan is not None:
+ element.attrib['colspan'] = colspan
+ else:
+ element.attrib['id'] = str(action.action.id)
+
# translate view
if Transaction().language != 'en':
for attr in ('string', 'sum', 'confirm', 'help'):
diff -r 38b32161f535 -r 45787f01dc3e trytond/tests/modelview.py
--- a/trytond/tests/modelview.py Sun Apr 12 23:53:02 2020 +0200
+++ b/trytond/tests/modelview.py Mon Apr 13 12:21:55 2020 +0200
@@ -99,6 +99,16 @@
return {'url': 'http://www.tryton.org/'}
+class ModelViewLink(ModelView):
+ "ModelView Link"
+ __name__ = 'test.modelview.link'
+
+
+class ModelViewLinkTarget(ModelSQL):
+ "ModelView Link Target"
+ __name__ = 'test.modelview.link.target'
+
+
class ModelViewRPC(ModelView):
'ModelView RPC'
__name__ = 'test.modelview.rpc'
@@ -202,6 +212,8 @@
ModelViewButton,
ModelViewButtonDepends,
ModelViewButtonAction,
+ ModelViewLink,
+ ModelViewLinkTarget,
ModelViewRPC,
ModelViewEmptyPage,
ModelViewCircularDepends,
diff -r 38b32161f535 -r 45787f01dc3e trytond/tests/modelview.xml
--- a/trytond/tests/modelview.xml Sun Apr 12 23:53:02 2020 +0200
+++ b/trytond/tests/modelview.xml Mon Apr 13 12:21:55 2020 +0200
@@ -35,6 +35,23 @@
<field name="url">http://www.example.com/</field>
</record>
+ <record model="ir.ui.view" id="test_modelview_link">
+ <field name="model">test.modelview.link</field>
+ <field name="type">form</field>
+ <field name="arch" type="xml">
+ <![CDATA[
+ <form>
+ <link name="tests.test_modelview_link_action"/>
+ </form>
+ ]]>
+ </field>
+ </record>
+
+ <record model="ir.action.act_window" id="test_modelview_link_action">
+ <field name="name">Link</field>
+ <field name="res_model">test.modelview.link.target</field>
+ </record>
+
<record model="ir.ui.view" id="test_modelview_view_attributes">
<field name="model">test.modelview.view_attributes</field>
<field name="type">form</field>
diff -r 38b32161f535 -r 45787f01dc3e trytond/tests/test_modelview.py
--- a/trytond/tests/test_modelview.py Sun Apr 12 23:53:02 2020 +0200
+++ b/trytond/tests/test_modelview.py Mon Apr 13 12:21:55 2020 +0200
@@ -385,6 +385,41 @@
self.assertEqual(action['url'], 'http://www.tryton.org/')
@with_transaction()
+ def test_link(self):
+ "Test link in view"
+ pool = Pool()
+ TestModel = pool.get('test.modelview.link')
+
+ arch = TestModel.fields_view_get()['arch']
+ parser = etree.XMLParser()
+ tree = etree.fromstring(arch, parser=parser)
+ link, = tree.xpath('//link')
+
+ self.assertTrue(link.attrib['id'])
+ self.assertIsInstance(int(link.attrib['id']), int)
+
+ @with_transaction()
+ def test_link_without_read_access(self):
+ "Test link in view without read access"
+ pool = Pool()
+ TestModel = pool.get('test.modelview.link')
+ Model = pool.get('ir.model')
+ ModelAccess = pool.get('ir.model.access')
+
+ model, = Model.search([('model', '=', 'test.modelview.link.target')])
+ access = ModelAccess(model=model, group=None, perm_read=False)
+ access.save()
+
+ arch = TestModel.fields_view_get()['arch']
+ parser = etree.XMLParser()
+ tree = etree.fromstring(arch, parser=parser)
+ links = tree.xpath('//link')
+ labels = tree.xpath('//label')
+
+ self.assertFalse(links)
+ self.assertTrue(labels)
+
+ @with_transaction()
def test_rpc_setup(self):
"Testing the computation of the RPC methods"
pool = Pool()