--- a/entities/schemaobjs.py Tue Apr 13 12:19:24 2010 +0200
+++ b/entities/schemaobjs.py Tue Apr 13 13:21:10 2010 +0200
@@ -162,6 +162,9 @@
fetch_attrs, fetch_order = fetch_config(['exprtype', 'mainvars', 'expression'])
def dc_title(self):
+ return self.expression or u''
+
+ def dc_long_title(self):
return '%s(%s)' % (self.exprtype, self.expression or u'')
@property
--- a/entities/wfobjs.py Tue Apr 13 12:19:24 2010 +0200
+++ b/entities/wfobjs.py Tue Apr 13 13:21:10 2010 +0200
@@ -174,7 +174,7 @@
fired by the logged user
"""
__regid__ = 'BaseTransition'
- fetch_attrs, fetch_order = fetch_config(['name'])
+ fetch_attrs, fetch_order = fetch_config(['name', 'type'])
def __init__(self, *args, **kwargs):
if self.__regid__ == 'BaseTransition':
--- a/i18n/en.po Tue Apr 13 12:19:24 2010 +0200
+++ b/i18n/en.po Tue Apr 13 13:21:10 2010 +0200
@@ -30,6 +30,9 @@
msgid " from state %(fromstate)s to state %(tostate)s\n"
msgstr ""
+msgid " :"
+msgstr ""
+
#, python-format
msgid "%(attr)s set to %(newvalue)s"
msgstr ""
@@ -603,6 +606,9 @@
msgid "The view %s could not be found"
msgstr ""
+msgid "There is no default workflow"
+msgstr ""
+
msgid "This BaseTransition"
msgstr "This abstract transition"
@@ -1514,9 +1520,6 @@
msgid "condition"
msgstr "condition"
-msgid "condition:"
-msgstr "condtion:"
-
msgctxt "RQLExpression"
msgid "condition_object"
msgstr "condition of"
@@ -1524,6 +1527,9 @@
msgid "condition_object"
msgstr "condition of"
+msgid "conditions"
+msgstr ""
+
msgid "config mode"
msgstr ""
@@ -2385,10 +2391,6 @@
msgid "granted to groups"
msgstr ""
-#, python-format
-msgid "graphical representation of %s"
-msgstr ""
-
msgid "graphical representation of the instance'schema"
msgstr ""
@@ -2412,9 +2414,6 @@
msgid "groups to which the permission is granted"
msgstr ""
-msgid "groups:"
-msgstr ""
-
msgid "guests"
msgstr ""
@@ -2790,6 +2789,9 @@
msgid "more actions"
msgstr ""
+msgid "more info about this workflow"
+msgstr ""
+
msgid "multiple edit"
msgstr ""
@@ -3013,6 +3015,9 @@
msgid "permission"
msgstr ""
+msgid "permissions"
+msgstr ""
+
msgid "permissions for entities"
msgstr ""
@@ -3931,6 +3936,12 @@
msgid "wf_info_for_object"
msgstr "workflow history"
+msgid "wf_tab_info"
+msgstr ""
+
+msgid "wfgraph"
+msgstr ""
+
msgid ""
"when multiple addresses are equivalent (such as python-projects@logilab.org "
"and python-projects@lists.logilab.org), set this to indicate which is the "
--- a/i18n/es.po Tue Apr 13 12:19:24 2010 +0200
+++ b/i18n/es.po Tue Apr 13 13:21:10 2010 +0200
@@ -35,6 +35,9 @@
msgid " from state %(fromstate)s to state %(tostate)s\n"
msgstr " del estado %(fromstate)s hacia el estado %(tostate)s\n"
+msgid " :"
+msgstr ""
+
#, python-format
msgid "%(attr)s set to %(newvalue)s"
msgstr ""
@@ -611,6 +614,9 @@
msgid "The view %s could not be found"
msgstr "La vista %s no ha podido ser encontrada"
+msgid "There is no default workflow"
+msgstr ""
+
msgid "This BaseTransition"
msgstr ""
@@ -1545,9 +1551,6 @@
msgid "condition"
msgstr ""
-msgid "condition:"
-msgstr "condición:"
-
msgctxt "RQLExpression"
msgid "condition_object"
msgstr ""
@@ -1555,6 +1558,9 @@
msgid "condition_object"
msgstr "condición de"
+msgid "conditions"
+msgstr ""
+
msgid "config mode"
msgstr ""
@@ -2435,10 +2441,6 @@
msgid "granted to groups"
msgstr "Otorgado a los grupos"
-#, python-format
-msgid "graphical representation of %s"
-msgstr ""
-
msgid "graphical representation of the instance'schema"
msgstr ""
@@ -2462,9 +2464,6 @@
msgid "groups to which the permission is granted"
msgstr "Grupos quienes tienen otorgada esta autorización"
-msgid "groups:"
-msgstr "Grupos :"
-
msgid "guests"
msgstr "Invitados"
@@ -2858,6 +2857,9 @@
msgid "more actions"
msgstr "mas acciones"
+msgid "more info about this workflow"
+msgstr ""
+
msgid "multiple edit"
msgstr "Edicion multiple"
@@ -3086,6 +3088,9 @@
msgid "permission"
msgstr "Permiso"
+msgid "permissions"
+msgstr ""
+
msgid "permissions for entities"
msgstr "autorizaciónes para entidades"
@@ -4018,6 +4023,12 @@
msgid "wf_info_for_object"
msgstr "historial de transiciones"
+msgid "wf_tab_info"
+msgstr ""
+
+msgid "wfgraph"
+msgstr ""
+
msgid ""
"when multiple addresses are equivalent (such as python-projects@logilab.org "
"and python-projects@lists.logilab.org), set this to indicate which is the "
@@ -4219,6 +4230,9 @@
#~ msgid "comment:"
#~ msgstr "Comentario:"
+#~ msgid "condition:"
+#~ msgstr "condición:"
+
#~ msgid "copy edition"
#~ msgstr "Edición de una copia"
@@ -4314,6 +4328,9 @@
#~ msgid "groups allowed to update entities of this type"
#~ msgstr "Grupos autorizados a actualizar entidades de este tipo"
+#~ msgid "groups:"
+#~ msgstr "Grupos :"
+
#~ msgid "home"
#~ msgstr "Inicio"
--- a/i18n/fr.po Tue Apr 13 12:19:24 2010 +0200
+++ b/i18n/fr.po Tue Apr 13 13:21:10 2010 +0200
@@ -35,6 +35,9 @@
msgid " from state %(fromstate)s to state %(tostate)s\n"
msgstr " de l'état %(fromstate)s vers l'état %(tostate)s\n"
+msgid " :"
+msgstr ""
+
#, python-format
msgid "%(attr)s set to %(newvalue)s"
msgstr "%(attr)s modifié à %(newvalue)s"
@@ -622,6 +625,9 @@
msgid "The view %s could not be found"
msgstr "La vue %s est introuvable"
+msgid "There is no default workflow"
+msgstr "Ce type d'entité n'a pas de workflow par défault"
+
msgid "This BaseTransition"
msgstr "Cette transition abstraite"
@@ -1565,9 +1571,6 @@
msgid "condition"
msgstr "condition"
-msgid "condition:"
-msgstr "condition :"
-
msgctxt "RQLExpression"
msgid "condition_object"
msgstr "condition de"
@@ -1575,6 +1578,9 @@
msgid "condition_object"
msgstr "condition de"
+msgid "conditions"
+msgstr "conditions"
+
msgid "config mode"
msgstr "mode de configuration"
@@ -2374,7 +2380,7 @@
msgstr "suivez ce lien pour plus d'information sur ce %s"
msgid "follow this link if javascript is deactivated"
-msgstr ""
+msgstr "suivez ce lien si javascript est désactivé"
msgid "for_user"
msgstr "pour l'utilisateur"
@@ -2471,10 +2477,6 @@
msgid "granted to groups"
msgstr "accordée aux groupes"
-#, python-format
-msgid "graphical representation of %s"
-msgstr "représentation graphique de %s"
-
msgid "graphical representation of the instance'schema"
msgstr "représentation graphique du schéma de l'instance"
@@ -2499,9 +2501,6 @@
msgid "groups to which the permission is granted"
msgstr "groupes auquels cette permission est donnée"
-msgid "groups:"
-msgstr "groupes :"
-
msgid "guests"
msgstr "invités"
@@ -2896,6 +2895,9 @@
msgid "more actions"
msgstr "plus d'actions"
+msgid "more info about this workflow"
+msgstr "plus d'information sur ce workflow"
+
msgid "multiple edit"
msgstr "édition multiple"
@@ -3122,6 +3124,9 @@
msgid "permission"
msgstr "permission"
+msgid "permissions"
+msgstr "permissions"
+
msgid "permissions for entities"
msgstr "permissions pour les entités"
@@ -4062,6 +4067,12 @@
msgid "wf_info_for_object"
msgstr "historique des transitions"
+msgid "wf_tab_info"
+msgstr "description"
+
+msgid "wfgraph"
+msgstr "image du workflow"
+
msgid ""
"when multiple addresses are equivalent (such as python-projects@logilab.org "
"and python-projects@lists.logilab.org), set this to indicate which is the "
--- a/web/data/cubicweb.css Tue Apr 13 12:19:24 2010 +0200
+++ b/web/data/cubicweb.css Tue Apr 13 13:21:10 2010 +0200
@@ -63,7 +63,7 @@
text-decoration: underline;
}
-a img {
+a img, img {
border: none;
text-align: center;
}
--- a/web/views/cwuser.py Tue Apr 13 12:19:24 2010 +0200
+++ b/web/views/cwuser.py Tue Apr 13 13:21:10 2010 +0200
@@ -71,3 +71,12 @@
if emailaddr:
self.w(u'<foaf:mbox>%s</foaf:mbox>\n' % xml_escape(emailaddr))
self.w(u'</foaf:Person>\n')
+
+class CWGroupInContextView(EntityView):
+ __regid__ = 'incontext'
+ __select__ = implements('CWGroup')
+ def cell_call(self, row, col):
+ self._cw.add_css('cubicweb.acl.css')
+ entity = self.cw_rset.complete_entity(row, col)
+ self.w(u'<a href="%s" class="%s">%s</a>' % (
+ entity.absolute_url(), entity.name, entity.printable_value('name')))
--- a/web/views/schema.py Tue Apr 13 12:19:24 2010 +0200
+++ b/web/views/schema.py Tue Apr 13 13:21:10 2010 +0200
@@ -313,18 +313,25 @@
entity = self.cw_rset.get_entity(row, col)
if entity.default_workflow:
wf = entity.default_workflow[0]
- self.w(u'<h1>%s (%s)</h1>' % (wf.name, self._cw._('default')))
- self.wf_image(wf)
+ if len(entity.reverse_workflow_of) > 1:
+ self.w(u'<h1>%s (%s)</h1>'
+ % (wf.name, self._cw._('default_workflow')))
+ self.display_workflow(wf)
+ defaultwfeid = wf.eid
+ else:
+ self.w(u'<div class="error">%s</div>'
+ % self._cw._('There is no default workflow'))
+ defaultwfeid = None
for altwf in entity.reverse_workflow_of:
- if altwf.eid == wf.eid:
+ if altwf.eid == defaultwfeid:
continue
self.w(u'<h1>%s</h1>' % altwf.name)
- self.wf_image(altwf)
+ self.display_workflow(altwf)
- def wf_image(self, wf):
- self.w(u'<img src="%s" alt="%s"/>' % (
- xml_escape(wf.absolute_url(vid='wfgraph')),
- xml_escape(self._cw._('graphical representation of %s') % wf.name)))
+ def display_workflow(self, wf):
+ self.w(wf.view('wfgraph'))
+ self.w('<a href="%s">%s</a>' % (
+ wf.absolute_url(), self._cw._('more info about this workflow')))
# CWRType ######################################################################
--- a/web/views/workflow.py Tue Apr 13 12:19:24 2010 +0200
+++ b/web/views/workflow.py Tue Apr 13 13:21:10 2010 +0200
@@ -11,6 +11,9 @@
__docformat__ = "restructuredtext en"
_ = unicode
+import tempfile
+import os
+
from logilab.mtconverter import xml_escape
from logilab.common.graph import escape, GraphGenerator, DotBackend
@@ -24,6 +27,7 @@
from cubicweb.web import uicfg, stdmsgs, action, component, form, action
from cubicweb.web import formfields as ff, formwidgets as fwdgs
from cubicweb.web.views import TmpFileViewMixin, forms, primary, autoform
+from cubicweb.web.views.tabs import TabbedPrimaryView, PrimaryTab
_pvs = uicfg.primaryview_section
_pvs.tag_subject_of(('Workflow', 'initial_state', '*'), 'hidden')
@@ -187,6 +191,7 @@
_pvs.tag_subject_of(('Workflow', 'initial_state', '*'), 'hidden')
_pvs.tag_object_of(('*', 'state_of', 'Workflow'), 'hidden')
_pvs.tag_object_of(('*', 'transition_of', 'Workflow'), 'hidden')
+_pvs.tag_object_of(('*', 'default_workflow', 'Workflow'), 'hidden')
_abaa = uicfg.actionbox_appearsin_addmenu
_abaa.tag_subject_of(('BaseTransition', 'condition', 'RQLExpression'), False)
@@ -198,14 +203,10 @@
_abaa.tag_object_of(('Transition', 'transition_of', 'Workflow'), True)
_abaa.tag_object_of(('WorkflowTransition', 'transition_of', 'Workflow'), True)
-class WorkflowPrimaryView(primary.PrimaryView):
+class WorkflowPrimaryView(TabbedPrimaryView):
__select__ = implements('Workflow')
-
- def render_entity_attributes(self, entity):
- self.w(entity.view('reledit', rtype='description'))
- self.w(u'<img src="%s" alt="%s"/>' % (
- xml_escape(entity.absolute_url(vid='wfgraph')),
- xml_escape(self._cw._('graphical workflow for %s') % entity.name)))
+ tabs = [ _('wf_tab_info'), _('wfgraph'),]
+ default_tab = 'wf_tab_info'
class CellView(view.EntityView):
@@ -225,6 +226,59 @@
self.w(xml_escape(self._cw.view('textincontext', self.cw_rset,
row=row, col=col)))
+class WorkflowTabTextView(PrimaryTab):
+ __regid__ = 'wf_tab_info'
+ __select__ = PrimaryTab.__select__ & one_line_rset() & implements('Workflow')
+
+ def render_entity_attributes(self, entity):
+ _ = self._cw._
+ self.w(u'<div>%s</div>' % (entity.printable_value('description')))
+ self.w(u'<span>%s%s</span>' % (_("workflow_of").capitalize(), _(" :")))
+ html = []
+ for e in entity.workflow_of:
+ view = e.view('outofcontext')
+ if entity.eid == e.default_workflow[0].eid:
+ view += u' <span>[%s]</span>' % _('default_workflow')
+ html.append(view)
+ self.w(', '.join(v for v in html))
+ self.w(u'<h2>%s</h2>' % _("Transition_plural"))
+ rset = self._cw.execute(
+ 'Any T,T,DS,T,TT ORDERBY TN WHERE T transition_of WF, WF eid %(x)s,'
+ 'T type TT, T name TN, T destination_state DS?', {'x': entity.eid})
+ self.wview('editable-table', rset, 'null',
+ cellvids={ 1: 'trfromstates', 2: 'outofcontext', 3:'trsecurity',},
+ headers = (_('Transition'), _('from_state'),
+ _('to_state'), _('permissions'), _('type') ),
+ )
+
+
+class TransitionSecurityTextView(view.EntityView):
+ __regid__ = 'trsecurity'
+ __select__ = implements('Transition')
+
+ def cell_call(self, row, col):
+ _ = self._cw._
+ entity = self.cw_rset.get_entity(self.cw_row, self.cw_col)
+ if entity.require_group:
+ self.w(u'<div>%s%s %s</div>' %
+ (_('groups'), _(" :"),
+ u', '.join((g.view('incontext') for g
+ in entity.require_group))))
+ if entity.condition:
+ self.w(u'<div>%s%s %s</div>' %
+ ( _('conditions'), _(" :"),
+ u'<br/>'.join((e.dc_title() for e
+ in entity.condition))))
+
+class TransitionAllowedTextView(view.EntityView):
+ __regid__ = 'trfromstates'
+ __select__ = implements('Transition')
+
+ def cell_call(self, row, col):
+ entity = self.cw_rset.get_entity(self.cw_row, self.cw_col)
+ self.w(u', '.join((e.view('outofcontext') for e
+ in entity.reverse_allowed_transition)))
+
# workflow entity types edition ################################################
@@ -284,24 +338,18 @@
def node_properties(self, stateortransition):
"""return default DOT drawing options for a state or transition"""
props = {'label': stateortransition.printable_value('name'),
- 'fontname': 'Courier'}
+ 'fontname': 'Courier', 'fontsize':10,
+ 'href': stateortransition.absolute_url(),
+ }
if hasattr(stateortransition, 'state_of'):
props['shape'] = 'box'
props['style'] = 'filled'
if stateortransition.reverse_initial_state:
- props['color'] = '#88CC88'
+ props['fillcolor'] = '#88CC88'
else:
props['shape'] = 'ellipse'
descr = []
tr = stateortransition
- if tr.require_group:
- descr.append('%s %s'% (
- self._('groups:'),
- ','.join(g.printable_value('name') for g in tr.require_group)))
- if tr.condition:
- descr.append('%s %s'% (
- self._('condition:'),
- ' | '.join(e.expression for e in tr.condition)))
if descr:
props['label'] += escape('\n'.join(descr))
return props
@@ -331,17 +379,39 @@
yield transition.eid, outgoingstate.eid, transition
+class WorkflowGraphView(view.EntityView):
+ __regid__ = 'wfgraph'
+ __select__ = EntityView.__select__ & one_line_rset() & implements('Workflow')
+
+ def cell_call(self, row, col):
+ entity = self.cw_rset.get_entity(row, col)
+ visitor = WorkflowVisitor(entity)
+ prophdlr = WorkflowDotPropsHandler(self._cw)
+ wfname = 'workflow%s' % str(entity.eid)
+ generator = GraphGenerator(DotBackend(wfname, None,
+ ratio='compress', size='30,10'))
+ # map file
+ pmap, mapfile = tempfile.mkstemp(".map", wfname)
+ os.close(pmap)
+ # image file
+ fd, tmpfile = tempfile.mkstemp('.png')
+ os.close(fd)
+ generator.generate(visitor, prophdlr, tmpfile, mapfile)
+ self.w(u'<img src="%s" alt="%s" usemap="#%s" />' % (
+ xml_escape(entity.absolute_url(vid='wfimage', tmpfile=tmpfile)),
+ xml_escape(self._cw._('graphical workflow for %s') % entity.name),
+ wfname))
+ stream = open(mapfile, 'r').read()
+ stream = stream.decode(self._cw.encoding)
+ self.w(stream)
+ os.unlink(mapfile)
+
class WorkflowImageView(TmpFileViewMixin, view.EntityView):
- __regid__ = 'wfgraph'
+ __regid__ = 'wfimage'
__select__ = implements('Workflow')
content_type = 'image/png'
- def _generate(self, tmpfile):
- """display schema information for an entity"""
- entity = self.cw_rset.get_entity(self.cw_row, self.cw_col)
- visitor = WorkflowVisitor(entity)
- prophdlr = WorkflowDotPropsHandler(self._cw)
- generator = GraphGenerator(DotBackend('workflow', 'LR',
- ratio='compress', size='30,12'))
- return generator.generate(visitor, prophdlr, tmpfile)
-
+ def cell_call(self, row=0, col=0):
+ tmpfile = self._cw.form.get('tmpfile', None)
+ self.w(open(tmpfile, 'rb').read())
+ os.unlink(tmpfile)