# HG changeset patch # User Aurelien Campeas # Date 1357839250 -3600 # Node ID e65af61bde7d8056fa184693791bfd75be72cbca # Parent 29652410c317c40f90c6e28e2d021dc47ebc9d9f [uicfg] uicfg.py moves from web/ to web/views/ (prepares #2406609) We are about to make uicfg selectable. Registrable / selectable views and helpers live in web/views. Hence the move. Backward compat is put in place. However CubicWeb imports of uicfg are updated to the new location. diff -r 29652410c317 -r e65af61bde7d devtools/devctl.py --- a/devtools/devctl.py Thu Jan 10 13:03:38 2013 +0100 +++ b/devtools/devctl.py Thu Jan 10 18:34:10 2013 +0100 @@ -97,7 +97,7 @@ break # fresh rtags from cubicweb import rtags - from cubicweb.web import uicfg + from cubicweb.web.views import uicfg rtags.RTAGS[:] = [] reload(uicfg) @@ -129,7 +129,7 @@ def _generate_schema_pot(w, vreg, schema, libconfig=None): from copy import deepcopy from cubicweb.i18n import add_msg - from cubicweb.web import uicfg + from cubicweb.web.views import uicfg from cubicweb.schema import NO_I18NCONTEXT, CONSTRAINTS w('# schema pot file, generated on %s\n' % datetime.now().strftime('%Y-%m-%d %H:%M:%S')) diff -r 29652410c317 -r e65af61bde7d doc/book/en/devweb/views/boxes.rst --- a/doc/book/en/devweb/views/boxes.rst Thu Jan 10 13:03:38 2013 +0100 +++ b/doc/book/en/devweb/views/boxes.rst Thu Jan 10 18:34:10 2013 +0100 @@ -15,7 +15,7 @@ which the box is displayed). By default, the links generated in this box are computed from the schema properties of the displayed entity, but it is possible to explicitly specify them thanks to the -`cubicweb.web.uicfg.rmode` *relation tag*: +`cubicweb.web.views.uicfg.rmode` *relation tag*: * `link`, indicates that a relation is in general created pointing to an existing entity and that we should not to display a link diff -r 29652410c317 -r e65af61bde7d doc/book/en/devweb/views/primary.rst --- a/doc/book/en/devweb/views/primary.rst Thu Jan 10 13:03:38 2013 +0100 +++ b/doc/book/en/devweb/views/primary.rst Thu Jan 10 18:34:10 2013 +0100 @@ -51,7 +51,7 @@ .. sourcecode:: python - from cubicweb.web import uicfg + from cubicweb.web.views import uicfg uicfg.primaryview_section.tag_attribute(('Blog', 'title'), 'hidden') **Relations** can be either displayed in one of the three sections or hidden. diff -r 29652410c317 -r e65af61bde7d doc/book/en/devweb/views/reledit.rst --- a/doc/book/en/devweb/views/reledit.rst Thu Jan 10 13:03:38 2013 +0100 +++ b/doc/book/en/devweb/views/reledit.rst Thu Jan 10 18:34:10 2013 +0100 @@ -68,7 +68,7 @@ The behaviour of reledited attributes/relations can be finely controlled using the reledit_ctrl rtag, defined in -:mod:`cubicweb.web.uicfg`. +:mod:`cubicweb.web.views.uicfg`. This rtag provides four control variables: @@ -93,7 +93,7 @@ .. sourcecode:: python from logilab.mtconverter import xml_escape - from cubicweb.web.uicfg import reledit_ctrl + from cubicweb.web.views.uicfg import reledit_ctrl reledit_ctrl.tag_attribute(('Company', 'name'), {'reload': lambda x:x.eid, 'default_value': xml_escape(u'')}) @@ -125,7 +125,7 @@ .. sourcecode:: python - import uicfg.primaryview_display_ctrl as _pvdc + from cubicweb.web.views.uicfg import primaryview_display_ctrl as _pvdc _pvdc.tag_attribute(('Company', 'name'), {'vid': 'incontext'}) To deactivate it everywhere it's used automatically, you may use the code snippet diff -r 29652410c317 -r e65af61bde7d doc/book/en/tutorials/advanced/part05_ui-advanced.rst --- a/doc/book/en/tutorials/advanced/part05_ui-advanced.rst Thu Jan 10 13:03:38 2013 +0100 +++ b/doc/book/en/tutorials/advanced/part05_ui-advanced.rst Thu Jan 10 18:34:10 2013 +0100 @@ -215,7 +215,7 @@ from logilab.common.decorators import monkeypatch from cubicweb import ValidationError - from cubicweb.web import uicfg, component + from cubicweb.web.views import uicfg, component from cubicweb.web.views import basecontrollers # hide displayed_on relation using uicfg since it will be displayed by the box below diff -r 29652410c317 -r e65af61bde7d web/formfields.py --- a/web/formfields.py Thu Jan 10 13:03:38 2013 +0100 +++ b/web/formfields.py Thu Jan 10 18:34:10 2013 +0100 @@ -79,7 +79,8 @@ from cubicweb import Binary, tags, uilib from cubicweb.utils import support_args from cubicweb.web import INTERNAL_FIELD_VALUE, ProcessFormError, eid_param, \ - formwidgets as fw, uicfg + formwidgets as fw +from cubicweb.web.views import uicfg class UnmodifiedField(Exception): diff -r 29652410c317 -r e65af61bde7d web/test/unittest_formwidgets.py --- a/web/test/unittest_formwidgets.py Thu Jan 10 13:03:38 2013 +0100 +++ b/web/test/unittest_formwidgets.py Thu Jan 10 18:34:10 2013 +0100 @@ -20,7 +20,7 @@ from logilab.common.testlib import TestCase, unittest_main, mock_object as mock from cubicweb.devtools import TestServerConfiguration, fake -from cubicweb.web import uicfg, formwidgets, formfields +from cubicweb.web import formwidgets, formfields from cubes.file.entities import File diff -r 29652410c317 -r e65af61bde7d web/test/unittest_reledit.py --- a/web/test/unittest_reledit.py Thu Jan 10 13:03:38 2013 +0100 +++ b/web/test/unittest_reledit.py Thu Jan 10 18:34:10 2013 +0100 @@ -20,7 +20,7 @@ """ from cubicweb.devtools.testlib import CubicWebTC -from cubicweb.web.uicfg import reledit_ctrl +from cubicweb.web.views.uicfg import reledit_ctrl class ReleditMixinTC(object): diff -r 29652410c317 -r e65af61bde7d web/test/unittest_uicfg.py --- a/web/test/unittest_uicfg.py Thu Jan 10 13:03:38 2013 +0100 +++ b/web/test/unittest_uicfg.py Thu Jan 10 18:34:10 2013 +0100 @@ -18,7 +18,8 @@ import copy from logilab.common.testlib import tag from cubicweb.devtools.testlib import CubicWebTC -from cubicweb.web import uicfg, uihelper, formwidgets as fwdgs +from cubicweb.web import uihelper, formwidgets as fwdgs +from cubicweb.web.views import uicfg abaa = uicfg.actionbox_appearsin_addmenu diff -r 29652410c317 -r e65af61bde7d web/test/unittest_views_editforms.py --- a/web/test/unittest_views_editforms.py Thu Jan 10 13:03:38 2013 +0100 +++ b/web/test/unittest_views_editforms.py Thu Jan 10 18:34:10 2013 +0100 @@ -22,7 +22,7 @@ from logilab.common.compat import any from cubicweb.devtools.testlib import CubicWebTC -from cubicweb.web import uicfg +from cubicweb.web.views import uicfg from cubicweb.web.formwidgets import AutoCompletionWidget AFFK = uicfg.autoform_field_kwargs diff -r 29652410c317 -r e65af61bde7d web/uicfg.py --- a/web/uicfg.py Thu Jan 10 13:03:38 2013 +0100 +++ b/web/uicfg.py Thu Jan 10 18:34:10 2013 +0100 @@ -15,422 +15,15 @@ # # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . -"""This module (``cubicweb.web.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 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) +""" +This module is now deprecated, see web.views.uicfg. """ __docformat__ = "restructuredtext en" from warnings import warn - -from logilab.common.compat import any - -from cubicweb import neg_role -from cubicweb.rtags import (RelationTags, RelationTagsBool, RelationTagsSet, - RelationTagsDict, NoTargetRelationTagsDict, - register_rtag, _ensure_str_key) -from cubicweb.schema import META_RTYPES, INTERNAL_TYPES, WORKFLOW_TYPES - - -# primary view configuration ################################################## - -def init_primaryview_section(rtag, sschema, rschema, oschema, role): - if rtag.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' - rtag.tag_relation((sschema, rschema, oschema, role), section) - -primaryview_section = RelationTags('primaryview_section', - init_primaryview_section, - frozenset(('attributes', 'relations', - 'sideboxes', 'hidden'))) - - -class DisplayCtrlRelationTags(NoTargetRelationTagsDict): - def __init__(self, *args, **kwargs): - super(DisplayCtrlRelationTags, self).__init__(*args, **kwargs) - self.counter = 0 - -def init_primaryview_display_ctrl(rtag, sschema, rschema, oschema, role): - if role == 'subject': - oschema = '*' - else: - sschema = '*' - rtag.counter += 1 - rtag.setdefault((sschema, rschema, oschema, role), 'order', rtag.counter) - -primaryview_display_ctrl = DisplayCtrlRelationTags('primaryview_display_ctrl', - init_primaryview_display_ctrl) +from cubicweb.web.views.uicfg import * -# 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): - def __init__(self, *args, **kwargs): - super(InitializableDict, self).__init__(*args, **kwargs) - register_rtag(self) - 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""" - - _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) - - @staticmethod - def _initfunc(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 - - @staticmethod - 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.iteritems(): - 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.iteritems()) - return rtags - +warn('[3.16] moved to cubicweb.web.views.uicfg', + DeprecationWarning, stacklevel=2) - 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 - permsoverrides = autoform_permissions_overrides - 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 ('attributes', 'metadata', 'hidden') - relpermission = permission - cw = entity._cw - 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) - -autoform_section = AutoformSectionRelationTags('autoform_section') - -# relations'field class -autoform_field = RelationTags('autoform_field') - -# relations'field explicit kwargs (given to field's __init__) -autoform_field_kwargs = RelationTagsDict('autoform_field_kwargs') - - -# set of tags of the form _on_new on relations. 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 -autoform_permissions_overrides = RelationTagsSet('autoform_permissions_overrides') - -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. - """ - _keys = frozenset('novalue_label novalue_include_rtype reload rvid edit_target'.split()) - - def tag_relation(self, key, tag): - for tagkey in tag.iterkeys(): - 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_reledit_ctrl(rtag, sschema, rschema, oschema, role): - values = rtag.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'): - rtag.warning('reledit: wrong value for edit_target on relation %s: %s', - rschema, edittarget) - edittarget = None - if not edittarget: - edittarget = 'related' if composite else 'rtype' - rtag.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) - rtag.tag_relation((sschema, rschema, oschema, role), - {'novalue_include_rtype': not showlabel}) - -reledit_ctrl = ReleditTags('reledit', init_reledit_ctrl) - -# boxes.EditBox configuration ################################################# - -# 'link' / 'create' relation tags, used to control the "add entity" submenu -def init_actionbox_appearsin_addmenu(rtag, sschema, rschema, oschema, role): - if rtag.get(sschema, rschema, oschema, role) is None: - if rschema in META_RTYPES: - rtag.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: - rtag.tag_relation((sschema, rschema, oschema, role), True) - -actionbox_appearsin_addmenu = RelationTagsBool('actionbox_appearsin_addmenu', - init_actionbox_appearsin_addmenu) diff -r 29652410c317 -r e65af61bde7d web/uihelper.py --- a/web/uihelper.py Thu Jan 10 13:03:38 2013 +0100 +++ b/web/uihelper.py Thu Jan 10 18:34:10 2013 +0100 @@ -45,7 +45,7 @@ """ __docformat__ = "restructuredtext en" -from cubicweb.web import uicfg +from cubicweb.web.views import uicfg from functools import partial def _tag_rel(rtag, etype, attr, desttype='*', *args, **kwargs): diff -r 29652410c317 -r e65af61bde7d web/views/actions.py --- a/web/views/actions.py Thu Jan 10 13:03:38 2013 +0100 +++ b/web/views/actions.py Thu Jan 10 18:34:10 2013 +0100 @@ -32,8 +32,8 @@ authenticated_user, match_user_groups, match_search_state, has_permission, has_add_permission, is_instance, debug_mode, ) -from cubicweb.web import uicfg, controller, action -from cubicweb.web.views import linksearch_select_url, vid_from_rset +from cubicweb.web import controller, action +from cubicweb.web.views import uicfg, linksearch_select_url, vid_from_rset class has_editable_relation(EntityPredicate): diff -r 29652410c317 -r e65af61bde7d web/views/autoform.py --- a/web/views/autoform.py Thu Jan 10 13:03:38 2013 +0100 +++ b/web/views/autoform.py Thu Jan 10 18:34:10 2013 +0100 @@ -135,9 +135,9 @@ match_kwargs, match_form_params, non_final_entity, specified_etype_implements) from cubicweb.utils import json_dumps -from cubicweb.web import (stdmsgs, uicfg, eid_param, +from cubicweb.web import (stdmsgs, eid_param, form as f, formwidgets as fw, formfields as ff) -from cubicweb.web.views import forms +from cubicweb.web.views import uicfg, forms from cubicweb.web.views.ajaxcontroller import ajaxfunc _AFS = uicfg.autoform_section diff -r 29652410c317 -r e65af61bde7d web/views/basecomponents.py --- a/web/views/basecomponents.py Thu Jan 10 13:03:38 2013 +0100 +++ b/web/views/basecomponents.py Thu Jan 10 18:34:10 2013 +0100 @@ -36,7 +36,7 @@ from cubicweb.schema import display_name from cubicweb.utils import wrap_on_write from cubicweb.uilib import toggle_action -from cubicweb.web import component, uicfg +from cubicweb.web import component from cubicweb.web.htmlwidgets import MenuWidget, PopupBoxMenu VISIBLE_PROP_DEF = { diff -r 29652410c317 -r e65af61bde7d web/views/bookmark.py --- a/web/views/bookmark.py Thu Jan 10 13:03:38 2013 +0100 +++ b/web/views/bookmark.py Thu Jan 10 18:34:10 2013 +0100 @@ -24,9 +24,8 @@ from cubicweb import Unauthorized, typed_eid from cubicweb.predicates import is_instance, one_line_rset -from cubicweb.web import (action, component, uicfg, htmlwidgets, - formwidgets as fw) -from cubicweb.web.views import primary +from cubicweb.web import action, component, htmlwidgets, formwidgets as fw +from cubicweb.web.views import uicfg, primary from cubicweb.web.views.ajaxcontroller import ajaxfunc _abaa = uicfg.actionbox_appearsin_addmenu diff -r 29652410c317 -r e65af61bde7d web/views/cwproperties.py --- a/web/views/cwproperties.py Thu Jan 10 13:03:38 2013 +0100 +++ b/web/views/cwproperties.py Thu Jan 10 18:34:10 2013 +0100 @@ -28,12 +28,12 @@ from cubicweb.predicates import (one_line_rset, none_rset, is_instance, match_user_groups, logged_user_in_rset) from cubicweb.view import StartupView -from cubicweb.web import uicfg, stdmsgs +from cubicweb.web import stdmsgs from cubicweb.web.form import FormViewMixIn from cubicweb.web.formfields import FIELDS, StringField from cubicweb.web.formwidgets import (Select, TextInput, Button, SubmitButton, FieldWidget) -from cubicweb.web.views import primary, formrenderers, editcontroller +from cubicweb.web.views import uicfg, primary, formrenderers, editcontroller from cubicweb.web.views.ajaxcontroller import ajaxfunc uicfg.primaryview_section.tag_object_of(('*', 'for_user', '*'), 'hidden') diff -r 29652410c317 -r e65af61bde7d web/views/cwsources.py --- a/web/views/cwsources.py Thu Jan 10 13:03:38 2013 +0100 +++ b/web/views/cwsources.py Thu Jan 10 18:34:10 2013 +0100 @@ -1,4 +1,4 @@ -# copyright 2010-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2010-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -33,9 +33,9 @@ match_user_groups, match_kwargs, match_view) from cubicweb.view import EntityView, StartupView from cubicweb.schema import META_RTYPES, VIRTUAL_RTYPES, display_name -from cubicweb.web import uicfg, formwidgets as wdgs, facet +from cubicweb.web import formwidgets as wdgs, facet from cubicweb.web.views import add_etype_button -from cubicweb.web.views import (tabs, actions, ibreadcrumbs, navigation, +from cubicweb.web.views import (uicfg, tabs, actions, ibreadcrumbs, navigation, tableview, pyviews) diff -r 29652410c317 -r e65af61bde7d web/views/cwuser.py --- a/web/views/cwuser.py Thu Jan 10 13:03:38 2013 +0100 +++ b/web/views/cwuser.py Thu Jan 10 18:34:10 2013 +0100 @@ -28,8 +28,8 @@ from cubicweb.schema import display_name from cubicweb.predicates import one_line_rset, is_instance, match_user_groups from cubicweb.view import EntityView, StartupView -from cubicweb.web import action, uicfg, formwidgets -from cubicweb.web.views import tabs, tableview, actions, add_etype_button +from cubicweb.web import action, formwidgets +from cubicweb.web.views import uicfg, tabs, tableview, actions, add_etype_button _pvs = uicfg.primaryview_section _pvs.tag_attribute(('CWUser', 'login'), 'hidden') diff -r 29652410c317 -r e65af61bde7d web/views/editforms.py --- a/web/views/editforms.py Thu Jan 10 13:03:38 2013 +0100 +++ b/web/views/editforms.py Thu Jan 10 18:34:10 2013 +0100 @@ -34,10 +34,10 @@ specified_etype_implements, is_instance) from cubicweb.view import EntityView from cubicweb.schema import display_name -from cubicweb.web import uicfg, stdmsgs, eid_param, \ +from cubicweb.web import stdmsgs, eid_param, \ formfields as ff, formwidgets as fw from cubicweb.web.form import FormViewMixIn, FieldNotFound -from cubicweb.web.views import forms, reledit +from cubicweb.web.views import uicfg, forms, reledit _pvdc = uicfg.primaryview_display_ctrl diff -r 29652410c317 -r e65af61bde7d web/views/emailaddress.py --- a/web/views/emailaddress.py Thu Jan 10 13:03:38 2013 +0100 +++ b/web/views/emailaddress.py Thu Jan 10 18:34:10 2013 +0100 @@ -24,8 +24,7 @@ from cubicweb.schema import display_name from cubicweb.predicates import is_instance from cubicweb import Unauthorized -from cubicweb.web import uicfg -from cubicweb.web.views import baseviews, primary, ibreadcrumbs +from cubicweb.web.views import uicfg, baseviews, primary, ibreadcrumbs _pvs = uicfg.primaryview_section _pvs.tag_subject_of(('*', 'use_email', '*'), 'attributes') diff -r 29652410c317 -r e65af61bde7d web/views/forms.py --- a/web/views/forms.py Thu Jan 10 13:03:38 2013 +0100 +++ b/web/views/forms.py Thu Jan 10 18:34:10 2013 +0100 @@ -56,7 +56,8 @@ from cubicweb.utils import support_args from cubicweb.predicates import non_final_entity, match_kwargs, one_line_rset from cubicweb.web import RequestError, ProcessFormError -from cubicweb.web import uicfg, form, formwidgets as fwdgs +from cubicweb.web import form, formwidgets as fwdgs +from cubicweb.web.views import uicfg from cubicweb.web.formfields import guess_field diff -r 29652410c317 -r e65af61bde7d web/views/primary.py --- a/web/views/primary.py Thu Jan 10 13:03:38 2013 +0100 +++ b/web/views/primary.py Thu Jan 10 18:34:10 2013 +0100 @@ -50,7 +50,8 @@ from cubicweb.predicates import match_kwargs, match_context from cubicweb.view import EntityView from cubicweb.schema import META_RTYPES, VIRTUAL_RTYPES, display_name -from cubicweb.web import uicfg, component +from cubicweb.web import component +from cubicweb.web.views import uicfg class PrimaryView(EntityView): diff -r 29652410c317 -r e65af61bde7d web/views/reledit.py --- a/web/views/reledit.py Thu Jan 10 13:03:38 2013 +0100 +++ b/web/views/reledit.py Thu Jan 10 18:34:10 2013 +0100 @@ -34,7 +34,8 @@ from cubicweb.utils import json, json_dumps from cubicweb.predicates import non_final_entity, match_kwargs from cubicweb.view import EntityView -from cubicweb.web import uicfg, stdmsgs +from cubicweb.web import stdmsgs +from cubicweb.web.views import uicfg from cubicweb.web.form import FieldNotFound from cubicweb.web.formwidgets import Button, SubmitButton from cubicweb.web.views.ajaxcontroller import ajaxfunc diff -r 29652410c317 -r e65af61bde7d web/views/schema.py --- a/web/views/schema.py Thu Jan 10 13:03:38 2013 +0100 +++ b/web/views/schema.py Thu Jan 10 18:34:10 2013 +0100 @@ -39,9 +39,9 @@ from cubicweb.utils import make_uid from cubicweb.view import EntityView, StartupView from cubicweb import tags, uilib -from cubicweb.web import action, facet, uicfg, schemaviewer +from cubicweb.web import action, facet, schemaviewer from cubicweb.web.views import TmpFileViewMixin -from cubicweb.web.views import primary, baseviews, tabs, tableview, ibreadcrumbs +from cubicweb.web.views import uicfg, primary, baseviews, tabs, tableview, ibreadcrumbs ALWAYS_SKIP_TYPES = BASE_TYPES | SCHEMA_TYPES SKIP_TYPES = (ALWAYS_SKIP_TYPES | META_RTYPES | SYSTEM_RTYPES | WORKFLOW_TYPES diff -r 29652410c317 -r e65af61bde7d web/views/startup.py --- a/web/views/startup.py Thu Jan 10 13:03:38 2013 +0100 +++ b/web/views/startup.py Thu Jan 10 18:34:10 2013 +0100 @@ -31,7 +31,8 @@ from cubicweb.view import StartupView from cubicweb.predicates import match_user_groups, is_instance from cubicweb.schema import display_name -from cubicweb.web import uicfg, httpcache +from cubicweb.web import httpcache +from cubicweb.web.views import uicfg class ManageView(StartupView): """:__regid__: *manage* diff -r 29652410c317 -r e65af61bde7d web/views/uicfg.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/views/uicfg.py Thu Jan 10 18:34:10 2013 +0100 @@ -0,0 +1,436 @@ +# copyright 2003-2011 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 . +"""This module (``cubicweb.web.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 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 logilab.common.compat import any + +from cubicweb import neg_role +from cubicweb.rtags import (RelationTags, RelationTagsBool, RelationTagsSet, + RelationTagsDict, NoTargetRelationTagsDict, + register_rtag, _ensure_str_key) +from cubicweb.schema import META_RTYPES, INTERNAL_TYPES, WORKFLOW_TYPES + + +# primary view configuration ################################################## + +def init_primaryview_section(rtag, sschema, rschema, oschema, role): + if rtag.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' + rtag.tag_relation((sschema, rschema, oschema, role), section) + +primaryview_section = RelationTags('primaryview_section', + init_primaryview_section, + frozenset(('attributes', 'relations', + 'sideboxes', 'hidden'))) + + +class DisplayCtrlRelationTags(NoTargetRelationTagsDict): + def __init__(self, *args, **kwargs): + super(DisplayCtrlRelationTags, self).__init__(*args, **kwargs) + self.counter = 0 + +def init_primaryview_display_ctrl(rtag, sschema, rschema, oschema, role): + if role == 'subject': + oschema = '*' + else: + sschema = '*' + rtag.counter += 1 + rtag.setdefault((sschema, rschema, oschema, role), 'order', rtag.counter) + +primaryview_display_ctrl = DisplayCtrlRelationTags('primaryview_display_ctrl', + init_primaryview_display_ctrl) + + +# 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): + def __init__(self, *args, **kwargs): + super(InitializableDict, self).__init__(*args, **kwargs) + register_rtag(self) + 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""" + + _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) + + @staticmethod + def _initfunc(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 + + @staticmethod + 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.iteritems(): + 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.iteritems()) + 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 + permsoverrides = autoform_permissions_overrides + 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 ('attributes', 'metadata', 'hidden') + relpermission = permission + cw = entity._cw + 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) + +autoform_section = AutoformSectionRelationTags('autoform_section') + +# relations'field class +autoform_field = RelationTags('autoform_field') + +# relations'field explicit kwargs (given to field's __init__) +autoform_field_kwargs = RelationTagsDict('autoform_field_kwargs') + + +# set of tags of the form _on_new on relations. 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 +autoform_permissions_overrides = RelationTagsSet('autoform_permissions_overrides') + +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. + """ + _keys = frozenset('novalue_label novalue_include_rtype reload rvid edit_target'.split()) + + def tag_relation(self, key, tag): + for tagkey in tag.iterkeys(): + 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_reledit_ctrl(rtag, sschema, rschema, oschema, role): + values = rtag.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'): + rtag.warning('reledit: wrong value for edit_target on relation %s: %s', + rschema, edittarget) + edittarget = None + if not edittarget: + edittarget = 'related' if composite else 'rtype' + rtag.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) + rtag.tag_relation((sschema, rschema, oschema, role), + {'novalue_include_rtype': not showlabel}) + +reledit_ctrl = ReleditTags('reledit', init_reledit_ctrl) + +# boxes.EditBox configuration ################################################# + +# 'link' / 'create' relation tags, used to control the "add entity" submenu +def init_actionbox_appearsin_addmenu(rtag, sschema, rschema, oschema, role): + if rtag.get(sschema, rschema, oschema, role) is None: + if rschema in META_RTYPES: + rtag.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: + rtag.tag_relation((sschema, rschema, oschema, role), True) + +actionbox_appearsin_addmenu = RelationTagsBool('actionbox_appearsin_addmenu', + init_actionbox_appearsin_addmenu) diff -r 29652410c317 -r e65af61bde7d web/views/workflow.py --- a/web/views/workflow.py Thu Jan 10 13:03:38 2013 +0100 +++ b/web/views/workflow.py Thu Jan 10 18:34:10 2013 +0100 @@ -36,10 +36,10 @@ score_entity, is_instance, adaptable) from cubicweb.view import EntityView from cubicweb.schema import display_name -from cubicweb.web import uicfg, stdmsgs, action, component, form, action +from cubicweb.web import stdmsgs, action, component, form, action from cubicweb.web import formfields as ff, formwidgets as fwdgs from cubicweb.web.views import TmpFileViewMixin -from cubicweb.web.views import forms, primary, ibreadcrumbs +from cubicweb.web.views import uicfg, forms, primary, ibreadcrumbs from cubicweb.web.views.tabs import TabbedPrimaryView, PrimaryTab from cubicweb.web.views.dotgraphview import DotGraphView, DotPropsHandler