--- a/web/views/uicfg.py Mon Jan 04 18:40:30 2016 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,693 +0,0 @@
-# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
-# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
-#
-# This file is part of CubicWeb.
-#
-# CubicWeb is free software: you can redistribute it and/or modify it under the
-# terms of the GNU Lesser General Public License as published by the Free
-# Software Foundation, either version 2.1 of the License, or (at your option)
-# any later version.
-#
-# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-# details.
-#
-# You should have received a copy of the GNU Lesser General Public License along
-# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
-"""This module (``cubicweb.web.views.uicfg``) regroups a set of structures that may be
-used to configure various options of the generated web interface.
-
-To configure the interface generation, we use ``RelationTag`` objects.
-
-Index view configuration
-````````````````````````
-:indexview_etype_section:
- entity type category in the index/manage page. May be one of:
-
- * ``application``
- * ``system``
- * ``schema``
- * ``subobject`` (not displayed by default)
-
- By default only entities on the ``application`` category are shown.
-
-.. sourcecode:: python
-
- from cubicweb.web.views import uicfg
- # force hiding
- uicfg.indexview_etype_section['HideMe'] = 'subobject'
- # force display
- uicfg.indexview_etype_section['ShowMe'] = 'application'
-
-
-Actions box configuration
-`````````````````````````
-:actionbox_appearsin_addmenu:
- simple boolean relation tags used to control the "add entity" submenu.
- Relations whose rtag is True will appears, other won't.
-
-.. sourcecode:: python
-
- # Adds all subjects of the entry_of relation in the add menu of the ``Blog``
- # primary view
- uicfg.actionbox_appearsin_addmenu.tag_object_of(('*', 'entry_of', 'Blog'), True)
-"""
-__docformat__ = "restructuredtext en"
-
-from warnings import warn
-
-from six import string_types
-
-from cubicweb import neg_role
-from cubicweb.rtags import (RelationTags, RelationTagsBool, RelationTagsSet,
- RelationTagsDict, NoTargetRelationTagsDict,
- _ensure_str_key)
-from cubicweb.schema import META_RTYPES, INTERNAL_TYPES, WORKFLOW_TYPES
-
-
-# primary view configuration ##################################################
-
-class PrimaryViewSectionRelationTags(RelationTags):
- """primary view section configuration"""
- __regid__ = 'primaryview_section'
-
- _allowed_values = frozenset(('attributes', 'relations',
- 'sideboxes', 'hidden'))
-
- def _init(self, sschema, rschema, oschema, role):
- if self.get(sschema, rschema, oschema, role) is None:
- rdef = rschema.rdef(sschema, oschema)
- if rschema.final:
- if rschema.meta or sschema.is_metadata(rschema) \
- or oschema.type in ('Password', 'Bytes'):
- section = 'hidden'
- else:
- section = 'attributes'
- else:
- if rdef.role_cardinality(role) in '1+':
- section = 'attributes'
- elif rdef.composite == neg_role(role):
- section = 'relations'
- else:
- section = 'sideboxes'
- self.tag_relation((sschema, rschema, oschema, role), section)
-
-primaryview_section = PrimaryViewSectionRelationTags()
-
-
-class DisplayCtrlRelationTags(NoTargetRelationTagsDict):
- """primary view display controller configuration"""
- __regid__ = 'primaryview_display_ctrl'
-
- def __init__(self, *args, **kwargs):
- super(DisplayCtrlRelationTags, self).__init__(*args, **kwargs)
- self.counter = 0
-
- def _init(self, sschema, rschema, oschema, role):
- if role == 'subject':
- oschema = '*'
- else:
- sschema = '*'
- self.counter += 1
- self.setdefault((sschema, rschema, oschema, role),
- 'order',
- self.counter)
-
- def set_fields_order(self, etype, relations):
- """specify the field order in `etype` primary view.
-
- :param etype: the entity type as a string
- :param attrs: the ordered list of attribute names (or relations)
-
- `attrs` can be strings or 2-tuples (relname, role_of_etype_in_the_rel)
-
- Unspecified fields will be displayed after specified ones, their
- order being consistent with the schema definition.
-
- Examples:
-
- .. sourcecode:: python
-
- from cubicweb.web.views.uicfg import primaryview_display_ctrl as pvdc
- pvdc.set_fields_order('CWUser', ('firstname', ('in_group', 'subject'),
- 'surname', 'login'))
-
- """
- for index, relation in enumerate(relations):
- if not isinstance(relation, tuple):
- relation = (relation, 'subject')
- rtype, role = relation
- if role == 'subject':
- self.tag_subject_of((etype, rtype, '*'), {'order': index})
- else:
- self.tag_object_of((etype, rtype, '*'), {'order': index})
-
-
-primaryview_display_ctrl = DisplayCtrlRelationTags()
-
-
-# index view configuration ####################################################
-# entity type section in the index/manage page. May be one of
-# * 'application'
-# * 'system'
-# * 'schema'
-# * 'hidden'
-# * 'subobject' (not displayed by default)
-
-class InitializableDict(dict): # XXX not a rtag. Turn into an appobject?
- def __init__(self, *args, **kwargs):
- super(InitializableDict, self).__init__(*args, **kwargs)
- self.__defaults = dict(self)
-
- def init(self, schema, check=True):
- self.update(self.__defaults)
- for eschema in schema.entities():
- if eschema.final:
- continue
- if eschema.schema_entity():
- self.setdefault(eschema, 'schema')
- elif eschema in INTERNAL_TYPES or eschema in WORKFLOW_TYPES:
- self.setdefault(eschema, 'system')
- elif eschema.is_subobject(strict=True):
- self.setdefault(eschema, 'subobject')
- else:
- self.setdefault(eschema, 'application')
-
-indexview_etype_section = InitializableDict(
- EmailAddress='subobject',
- Bookmark='system',
- # entity types in the 'system' table by default (managers only)
- CWUser='system', CWGroup='system',
- )
-
-
-# autoform.AutomaticEntityForm configuration ##################################
-
-def _formsections_as_dict(formsections):
- result = {}
- for formsection in formsections:
- formtype, section = formsection.split('_', 1)
- result[formtype] = section
- return result
-
-def _card_and_comp(sschema, rschema, oschema, role):
- rdef = rschema.rdef(sschema, oschema)
- if role == 'subject':
- card = rdef.cardinality[0]
- composed = not rschema.final and rdef.composite == 'object'
- else:
- card = rdef.cardinality[1]
- composed = not rschema.final and rdef.composite == 'subject'
- return card, composed
-
-class AutoformSectionRelationTags(RelationTagsSet):
- """autoform relations'section"""
- __regid__ = 'autoform_section'
-
- _allowed_form_types = ('main', 'inlined', 'muledit')
- _allowed_values = {'main': ('attributes', 'inlined', 'relations',
- 'metadata', 'hidden'),
- 'inlined': ('attributes', 'inlined', 'hidden'),
- 'muledit': ('attributes', 'hidden'),
- }
-
- def init(self, schema, check=True):
- super(AutoformSectionRelationTags, self).init(schema, check)
- self.apply(schema, self._initfunc_step2)
-
- def _init(self, sschema, rschema, oschema, role):
- formsections = self.init_get(sschema, rschema, oschema, role)
- if formsections is None:
- formsections = self.tag_container_cls()
- if not any(tag.startswith('inlined') for tag in formsections):
- if not rschema.final:
- negsects = self.init_get(sschema, rschema, oschema, neg_role(role))
- if 'main_inlined' in negsects:
- formsections.add('inlined_hidden')
- key = _ensure_str_key( (sschema, rschema, oschema, role) )
- self._tagdefs[key] = formsections
-
- def _initfunc_step2(self, sschema, rschema, oschema, role):
- formsections = self.get(sschema, rschema, oschema, role)
- sectdict = _formsections_as_dict(formsections)
- if rschema in META_RTYPES:
- sectdict.setdefault('main', 'hidden')
- sectdict.setdefault('muledit', 'hidden')
- sectdict.setdefault('inlined', 'hidden')
- elif role == 'subject' and rschema in sschema.meta_attributes():
- # meta attribute, usually embeded by the described attribute's field
- # (eg RichTextField, FileField...)
- sectdict.setdefault('main', 'hidden')
- sectdict.setdefault('muledit', 'hidden')
- sectdict.setdefault('inlined', 'hidden')
- # ensure we have a tag for each form type
- if not 'main' in sectdict:
- if not rschema.final and (
- sectdict.get('inlined') == 'attributes' or
- 'inlined_attributes' in self.init_get(sschema, rschema, oschema,
- neg_role(role))):
- sectdict['main'] = 'hidden'
- elif sschema.is_metadata(rschema):
- sectdict['main'] = 'metadata'
- else:
- card, composed = _card_and_comp(sschema, rschema, oschema, role)
- if card in '1+':
- sectdict['main'] = 'attributes'
- if not 'muledit' in sectdict:
- sectdict['muledit'] = 'attributes'
- elif rschema.final:
- sectdict['main'] = 'attributes'
- else:
- sectdict['main'] = 'relations'
- if not 'muledit' in sectdict:
- sectdict['muledit'] = 'hidden'
- if sectdict['main'] == 'attributes':
- card, composed = _card_and_comp(sschema, rschema, oschema, role)
- if card in '1+' and not composed:
- sectdict['muledit'] = 'attributes'
- if not 'inlined' in sectdict:
- sectdict['inlined'] = sectdict['main']
- # recompute formsections and set it to avoid recomputing
- for formtype, section in sectdict.items():
- formsections.add('%s_%s' % (formtype, section))
-
- def tag_relation(self, key, formtype, section):
- if isinstance(formtype, tuple):
- for ftype in formtype:
- self.tag_relation(key, ftype, section)
- return
- assert formtype in self._allowed_form_types, \
- 'formtype should be in (%s), not %s' % (
- ','.join(self._allowed_form_types), formtype)
- assert section in self._allowed_values[formtype], \
- 'section for %s should be in (%s), not %s' % (
- formtype, ','.join(self._allowed_values[formtype]), section)
- rtags = self._tagdefs.setdefault(_ensure_str_key(key),
- self.tag_container_cls())
- # remove previous section for this form type if any
- if rtags:
- for tag in rtags.copy():
- if tag.startswith(formtype):
- rtags.remove(tag)
- rtags.add('%s_%s' % (formtype, section))
- return rtags
-
- def init_get(self, stype, rtype, otype, tagged):
- key = (stype, rtype, otype, tagged)
- rtags = {}
- for key in self._get_keys(stype, rtype, otype, tagged):
- tags = self._tagdefs.get(key, ())
- for tag in tags:
- assert '_' in tag, (tag, tags)
- section, value = tag.split('_', 1)
- rtags[section] = value
- cls = self.tag_container_cls
- rtags = cls('_'.join([section,value])
- for section,value in rtags.items())
- return rtags
-
- def get(self, *key):
- # overriden to avoid recomputing done in parent classes
- return self._tagdefs.get(key, ())
-
- def relations_by_section(self, entity, formtype, section, permission,
- strict=False):
- """return a list of (relation schema, target schemas, role) for the
- given entity matching categories and permission.
-
- `strict`:
- bool telling if having local role is enough (strict = False) or not
- """
- tag = '%s_%s' % (formtype, section)
- eschema = entity.e_schema
- cw = entity._cw
- permsoverrides = cw.vreg['uicfg'].select('autoform_permissions_overrides', cw, entity=entity)
- if entity.has_eid():
- eid = entity.eid
- else:
- eid = None
- strict = False
- if permission == 'update':
- assert section in ('attributes', 'metadata', 'hidden')
- relpermission = 'add'
- else:
- assert section not in ('metadata', 'hidden')
- relpermission = permission
- for rschema, targetschemas, role in eschema.relation_definitions(True):
- _targetschemas = []
- for tschema in targetschemas:
- # check section's tag first, potentially lower cost than
- # checking permission which may imply rql queries
- if not tag in self.etype_get(eschema, rschema, role, tschema):
- continue
- rdef = rschema.role_rdef(eschema, tschema, role)
- if rschema.final:
- if not rdef.has_perm(cw, permission, eid=eid,
- creating=eid is None):
- continue
- elif strict or not rdef.has_local_role(relpermission):
- if role == 'subject':
- if not rdef.has_perm(cw, relpermission, fromeid=eid):
- continue
- elif role == 'object':
- if not rdef.has_perm(cw, relpermission, toeid=eid):
- continue
- _targetschemas.append(tschema)
- if not _targetschemas:
- continue
- targetschemas = _targetschemas
- rdef = eschema.rdef(rschema, role=role, targettype=targetschemas[0])
- # XXX tag allowing to hijack the permission machinery when
- # permission is not verifiable until the entity is actually
- # created...
- if eid is None and '%s_on_new' % permission in permsoverrides.etype_get(eschema, rschema, role):
- yield (rschema, targetschemas, role)
- continue
- if not rschema.final and role == 'subject':
- # on relation with cardinality 1 or ?, we need delete perm as well
- # if the relation is already set
- if (relpermission == 'add'
- and rdef.role_cardinality(role) in '1?'
- and eid and entity.related(rschema.type, role)
- and not rdef.has_perm(cw, 'delete', fromeid=eid,
- toeid=entity.related(rschema.type, role)[0][0])):
- continue
- elif role == 'object':
- # on relation with cardinality 1 or ?, we need delete perm as well
- # if the relation is already set
- if (relpermission == 'add'
- and rdef.role_cardinality(role) in '1?'
- and eid and entity.related(rschema.type, role)
- and not rdef.has_perm(cw, 'delete', toeid=eid,
- fromeid=entity.related(rschema.type, role)[0][0])):
- continue
- yield (rschema, targetschemas, role)
-
- def hide_field(self, etype, attr, desttype='*', formtype='main'):
- """hide `attr` in `etype` forms.
-
- :param etype: the entity type as a string
- :param attr: the name of the attribute or relation to hide
- :param formtype: which form will be affected ('main', 'inlined', etc.),
- *main* by default.
-
- `attr` can be a string or 2-tuple (relname, role_of_etype_in_the_rel)
-
- Examples:
-
- .. sourcecode:: python
-
- from cubicweb.web.views.uicfg import autoform_section as afs
- afs.hide_field('CWUser', 'login')
- afs.hide_field('*', 'name')
- afs.hide_field('CWUser', 'use_email', formtype='inlined')
-
- """
- self._tag_etype_attr(etype, attr, desttype,
- formtype=formtype, section='hidden')
-
- def hide_fields(self, etype, attrs, formtype='main'):
- """simple for-loop wrapper around :func:`hide_field`.
-
- :param etype: the entity type as a string
- :param attrs: the ordered list of attribute names (or relations)
- :param formtype: which form will be affected ('main', 'inlined', etc.),
- *main* by default.
-
- `attrs` can be strings or 2-tuples (relname, role_of_etype_in_the_rel)
-
- Examples:
-
- .. sourcecode:: python
-
- from cubicweb.web.views.uicfg import autoform_section as afs
- afs.hide_fields('CWUser', ('login', ('use_email', 'subject')),
- formtype='inlined')
- """
- for attr in attrs:
- self.hide_field(etype, attr, formtype=formtype)
-
- def edit_inline(self, etype, attr, desttype='*', formtype=('main', 'inlined')):
- """edit `attr` with and inlined form.
-
- :param etype: the entity type as a string
- :param attr: the name of the attribute or relation
- :param desttype: the destination type(s) concerned, default is everything
- :param formtype: which form will be affected ('main', 'inlined', etc.),
- *main* and *inlined* by default.
-
- `attr` can be a string or 2-tuple (relname, role_of_etype_in_the_relation)
-
- Examples:
-
- .. sourcecode:: python
-
- from cubicweb.web.views.uicfg import autoform_section as afs
-
- afs.edit_inline('*', 'use_email')
- """
- self._tag_etype_attr(etype, attr, desttype, formtype=formtype,
- section='inlined')
-
- def edit_as_attr(self, etype, attr, desttype='*', formtype=('main', 'muledit')):
- """make `attr` appear in the *attributes* section of `etype` form.
-
- :param etype: the entity type as a string
- :param attr: the name of the attribute or relation
- :param desttype: the destination type(s) concerned, default is everything
- :param formtype: which form will be affected ('main', 'inlined', etc.),
- *main* and *muledit* by default.
-
- `attr` can be a string or 2-tuple (relname, role_of_etype_in_the_relation)
-
- Examples:
-
- .. sourcecode:: python
-
- from cubicweb.web.views.uicfg import autoform_section as afs
-
- afs.edit_as_attr('CWUser', 'in_group')
- """
- self._tag_etype_attr(etype, attr, desttype,
- formtype=formtype, section='attributes')
-
- def set_muledit_editable(self, etype, attrs):
- """make `attrs` appear in muledit form of `etype`.
-
- :param etype: the entity type as a string
- :param attrs: the ordered list of attribute names (or relations)
-
- `attrs` can be strings or 2-tuples (relname, role_of_etype_in_the_relation)
-
- Examples:
-
- .. sourcecode:: python
-
- from cubicweb.web.views.uicfg import autoform_section as afs
-
- afs.set_muledit_editable('CWUser', ('firstname', 'surname', 'in_group'))
- """
- for attr in attrs:
- self.edit_as_attr(self, etype, attr, formtype='muledit')
-
-autoform_section = AutoformSectionRelationTags()
-
-
-# relations'field class
-
-class AutoformFieldTags(RelationTags):
- __regid__ = 'autoform_field'
-
- def set_field(self, etype, attr, field):
- """sets the `attr` field of `etype`.
-
- :param etype: the entity type as a string
- :param attr: the name of the attribute or relation
-
- `attr` can be a string or 2-tuple (relname, role_of_etype_in_the_relation)
-
- """
- self._tag_etype_attr(etype, attr, '*', field)
-
-autoform_field = AutoformFieldTags()
-
-
-# relations'field explicit kwargs (given to field's __init__)
-
-class AutoformFieldKwargsTags(RelationTagsDict):
- __regid__ = 'autoform_field_kwargs'
-
- def set_fields_order(self, etype, attrs):
- """specify the field order in `etype` main edition form.
-
- :param etype: the entity type as a string
- :param attrs: the ordered list of attribute names (or relations)
-
- `attrs` can be strings or 2-tuples (relname, role_of_etype_in_the_rel)
-
- Unspecified fields will be displayed after specified ones, their
- order being consistent with the schema definition.
-
- Examples:
-
- .. sourcecode:: python
-
- from cubicweb.web.views.uicfg import autoform_field_kwargs as affk
- affk.set_fields_order('CWUser', ('firstname', 'surname', 'login'))
- affk.set_fields_order('CWUser', ('firstname', ('in_group', 'subject'),
- 'surname', 'login'))
-
- """
- for index, attr in enumerate(attrs):
- self._tag_etype_attr(etype, attr, '*', {'order': index})
-
- def set_field_kwargs(self, etype, attr, **kwargs):
- """tag `attr` field of `etype` with additional named paremeters.
-
- :param etype: the entity type as a string
- :param attr: the name of the attribute or relation
-
- `attr` can be a string or 2-tuple (relname, role_of_etype_in_the_relation)
-
- Examples:
-
- .. sourcecode:: python
-
- from cubicweb.web.views.uicfg import autoform_field_kwargs as affk
- affk.set_field_kwargs('Person', 'works_for', widget=fwdgs.AutoCompletionWidget())
- affk.set_field_kwargs('CWUser', 'login', label=_('login or email address'),
- widget=fwdgs.TextInput(attrs={'size': 30}))
- """
- self._tag_etype_attr(etype, attr, '*', kwargs)
-
-
-autoform_field_kwargs = AutoformFieldKwargsTags()
-
-
-# set of tags of the form <action>_on_new on relations. <action> is a
-# schema action (add/update/delete/read), and when such a tag is found
-# permissions checking is by-passed and supposed to be ok
-class AutoFormPermissionsOverrides(RelationTagsSet):
- __regid__ = 'autoform_permissions_overrides'
-
-autoform_permissions_overrides = AutoFormPermissionsOverrides()
-
-
-class ReleditTags(NoTargetRelationTagsDict):
- """Associate to relation a dictionary to control `reledit` (e.g. edition of
- attributes / relations from within views).
-
- Possible keys and associated values are:
-
- * `novalue_label`, alternative default value (shown when there is no value).
-
- * `novalue_include_rtype`, when `novalue_label` is not specified, this boolean
- flag control wether the generated default value should contains the
- relation label or not. Will be the opposite of the `showlabel` value found
- in the `primaryview_display_ctrl` rtag by default.
-
- * `reload`, boolean, eid (to reload to) or function taking subject and
- returning bool/eid. This is useful when editing a relation (or attribute)
- that impacts the url or another parts of the current displayed
- page. Defaults to False.
-
- * `rvid`, alternative view id (as str) for relation or composite edition.
- Default is 'autolimited'.
-
- * `edit_target`, may be either 'rtype' (to edit the relation) or 'related'
- (to edit the related entity). This controls whether to edit the relation
- or the target entity of the relation. Currently only one-to-one relations
- support target entity edition. By default, the 'related' option is taken
- whenever the relation is composite.
- """
- __regid__ = 'reledit'
- _keys = frozenset('novalue_label novalue_include_rtype reload rvid edit_target'.split())
-
- def tag_relation(self, key, tag):
- for tagkey in tag:
- assert tagkey in self._keys, 'tag %r not in accepted tags: %r' % (tag, self._keys)
- return super(ReleditTags, self).tag_relation(key, tag)
-
- def _init(self, sschema, rschema, oschema, role):
- values = self.get(sschema, rschema, oschema, role)
- if not rschema.final:
- composite = rschema.rdef(sschema, oschema).composite == role
- if role == 'subject':
- oschema = '*'
- else:
- sschema = '*'
- edittarget = values.get('edit_target')
- if edittarget not in (None, 'rtype', 'related'):
- self.warning('reledit: wrong value for edit_target on relation %s: %s',
- rschema, edittarget)
- edittarget = None
- if not edittarget:
- edittarget = 'related' if composite else 'rtype'
- self.tag_relation((sschema, rschema, oschema, role),
- {'edit_target': edittarget})
- if not 'novalue_include_rtype' in values:
- showlabel = primaryview_display_ctrl.get(
- sschema, rschema, oschema, role).get('showlabel', True)
- self.tag_relation((sschema, rschema, oschema, role),
- {'novalue_include_rtype': not showlabel})
-
-reledit_ctrl = ReleditTags()
-
-
-# boxes.EditBox configuration #################################################
-
-# 'link' / 'create' relation tags, used to control the "add entity" submenu
-
-class ActionBoxUicfg(RelationTagsBool):
- __regid__ = 'actionbox_appearsin_addmenu'
-
- def _init(self, sschema, rschema, oschema, role):
- if self.get(sschema, rschema, oschema, role) is None:
- if rschema in META_RTYPES:
- self.tag_relation((sschema, rschema, oschema, role), False)
- return
- rdef = rschema.rdef(sschema, oschema)
- if not rdef.role_cardinality(role) in '?1' and rdef.composite == role:
- self.tag_relation((sschema, rschema, oschema, role), True)
-
- def _tag_etype_attr(self, etype, attr, desttype='*', *args, **kwargs):
- if isinstance(attr, string_types):
- attr, role = attr, 'subject'
- else:
- attr, role = attr
- if role == 'subject':
- self.tag_subject_of((etype, attr, desttype), *args, **kwargs)
- else:
- self.tag_object_of((desttype, attr, etype), *args, **kwargs)
-
- def append_to_addmenu(self, etype, attr, createdtype='*'):
- """adds `attr` in the actions box *addrelated* submenu of `etype`.
-
- :param etype: the entity type as a string
- :param attr: the name of the attribute or relation to hide
- :param createdtype: the target type of the relation (optional, defaults to '*' (all possible types))
-
- `attr` can be a string or 2-tuple (relname, role_of_etype_in_the_relation)
-
- """
- self._tag_etype_attr(etype, attr, createdtype, True)
-
- def remove_from_addmenu(self, etype, attr, createdtype='*'):
- """removes `attr` from the actions box *addrelated* submenu of `etype`.
-
- :param etype: the entity type as a string
- :param attr: the name of the attribute or relation to hide
- :param createdtype: the target type of the relation (optional, defaults to '*' (all possible types))
-
- `attr` can be a string or 2-tuple (relname, role_of_etype_in_the_relation)
- """
- self._tag_etype_attr(etype, attr, createdtype, False)
-
-actionbox_appearsin_addmenu = ActionBoxUicfg()
-
-
-
-def registration_callback(vreg):
- vreg.register_all(globals().values(), __name__)
- indexview_etype_section.init(vreg.schema)