web/views/workflow.py
branchtls-sprint
changeset 1504 c6051f141807
parent 1398 5fe84a5f7035
child 1511 514e4e53a3c7
equal deleted inserted replaced
1503:5cc3afa14e4b 1504:c6051f141807
    21 from cubicweb.web.formfields import StringField,  RichTextField
    21 from cubicweb.web.formfields import StringField,  RichTextField
    22 from cubicweb.web.formwidgets import HiddenInput, SubmitButton, Button
    22 from cubicweb.web.formwidgets import HiddenInput, SubmitButton, Button
    23 from cubicweb.web.views import TmpFileViewMixin
    23 from cubicweb.web.views import TmpFileViewMixin
    24 from cubicweb.web.views.boxes import EditBox
    24 from cubicweb.web.views.boxes import EditBox
    25 
    25 
       
    26 _ = unicode
    26 
    27 
    27 EditBox.rmode.set_rtag('create', 'destination_state', 'subject', 'Transition')
    28 EditBox.rmode.set_rtag('create', 'destination_state', 'subject', 'Transition')
    28 EditBox.rmode.set_rtag('create', 'allowed_transition', 'object', 'Transition')
    29 EditBox.rmode.set_rtag('create', 'allowed_transition', 'object', 'Transition')
    29 EditBox.rmode.set_rtag('create', 'destination_state', 'object', 'State')
    30 EditBox.rmode.set_rtag('create', 'destination_state', 'object', 'State')
    30 EditBox.rmode.set_rtag('create', 'allowed_transition', 'subject', 'State')
    31 EditBox.rmode.set_rtag('create', 'allowed_transition', 'subject', 'State')
    32 
    33 
    33 # IWorkflowable views #########################################################
    34 # IWorkflowable views #########################################################
    34 
    35 
    35 class ChangeStateForm(form.EntityFieldsForm):
    36 class ChangeStateForm(form.EntityFieldsForm):
    36     id = 'changestate'
    37     id = 'changestate'
    37     
    38 
    38     __method = StringField(name='__method', initial='set_state',
    39     __method = StringField(name='__method', initial='set_state',
    39                            widget=HiddenInput)
    40                            widget=HiddenInput)
    40     state = StringField(widget=HiddenInput, eidparam=True)
    41     state = StringField(label=_('state'), eidparam=True, widget=HiddenInput)
    41     trcomment = RichTextField(eidparam=True)
    42     trcomment = RichTextField(label=_('trcomment'), eidparam=True)
    42     form_buttons = [SubmitButton(stdmsgs.YES),
    43     form_buttons = [SubmitButton(stdmsgs.YES),
    43                      Button(stdmsgs.NO, cwaction='cancel')]
    44                      Button(stdmsgs.NO, cwaction='cancel')]
    44 
    45 
    45         
    46 
    46 class ChangeStateFormView(FormViewMixIn, view.EntityView):
    47 class ChangeStateFormView(FormViewMixIn, view.EntityView):
    47     id = 'statuschange'
    48     id = 'statuschange'
    48     title = _('status change')
    49     title = _('status change')
    49     __select__ = implements(IWorkflowable) & match_form_params('treid')
    50     __select__ = implements(IWorkflowable) & match_form_params('treid')
    50 
    51 
    89         if self.vreg.schema.eschema('CWUser').has_perm(self.req, 'read'):
    90         if self.vreg.schema.eschema('CWUser').has_perm(self.req, 'read'):
    90             sel += ',U,C'
    91             sel += ',U,C'
    91             rql += ', WF owned_by U?'
    92             rql += ', WF owned_by U?'
    92             displaycols = range(5)
    93             displaycols = range(5)
    93             headers = (_('from_state'), _('to_state'), _('comment'), _('date'),
    94             headers = (_('from_state'), _('to_state'), _('comment'), _('date'),
    94                        _('CWUser'))            
    95                        _('CWUser'))
    95         else:
    96         else:
    96             sel += ',C'
    97             sel += ',C'
    97             displaycols = range(4)
    98             displaycols = range(4)
    98             headers = (_('from_state'), _('to_state'), _('comment'), _('date'))
    99             headers = (_('from_state'), _('to_state'), _('comment'), _('date'))
    99         rql = '%s %s, X eid %%(x)s' % (sel, rql)
   100         rql = '%s %s, X eid %%(x)s' % (sel, rql)
   109 # workflow entity types views #################################################
   110 # workflow entity types views #################################################
   110 
   111 
   111 class CellView(view.EntityView):
   112 class CellView(view.EntityView):
   112     id = 'cell'
   113     id = 'cell'
   113     __select__ = implements('TrInfo')
   114     __select__ = implements('TrInfo')
   114     
   115 
   115     def cell_call(self, row, col, cellvid=None):
   116     def cell_call(self, row, col, cellvid=None):
   116         self.w(self.entity(row, col).printable_value('comment'))
   117         self.w(self.entity(row, col).printable_value('comment'))
   117 
   118 
   118 
   119 
   119 class StateInContextView(view.EntityView):
   120 class StateInContextView(view.EntityView):
   120     """convenience trick, State's incontext view should not be clickable"""
   121     """convenience trick, State's incontext view should not be clickable"""
   121     id = 'incontext'
   122     id = 'incontext'
   122     __select__ = implements('State')
   123     __select__ = implements('State')
   123     
   124 
   124     def cell_call(self, row, col):
   125     def cell_call(self, row, col):
   125         self.w(html_escape(self.view('textincontext', self.rset,
   126         self.w(html_escape(self.view('textincontext', self.rset,
   126                                      row=row, col=col)))
   127                                      row=row, col=col)))
   127 
   128 
   128 
   129 
   129 # workflow images #############################################################
   130 # workflow images #############################################################
   130         
   131 
   131 class ViewWorkflowAction(action.Action):
   132 class ViewWorkflowAction(action.Action):
   132     id = 'workflow'
   133     id = 'workflow'
   133     __select__ = implements('CWEType') & has_related_entities('state_of', 'object')
   134     __select__ = implements('CWEType') & has_related_entities('state_of', 'object')
   134     
   135 
   135     category = 'mainactions'
   136     category = 'mainactions'
   136     title = _('view workflow')
   137     title = _('view workflow')
   137     def url(self):
   138     def url(self):
   138         entity = self.rset.get_entity(self.row or 0, self.col or 0)
   139         entity = self.rset.get_entity(self.row or 0, self.col or 0)
   139         return entity.absolute_url(vid='workflow')
   140         return entity.absolute_url(vid='workflow')
   140 
   141 
   141         
   142 
   142 class CWETypeWorkflowView(view.EntityView):
   143 class CWETypeWorkflowView(view.EntityView):
   143     id = 'workflow'
   144     id = 'workflow'
   144     __select__ = implements('CWEType')
   145     __select__ = implements('CWEType')
   145     cache_max_age = 60*60*2 # stay in http cache for 2 hours by default 
   146     cache_max_age = 60*60*2 # stay in http cache for 2 hours by default
   146     
   147 
   147     def cell_call(self, row, col, **kwargs):
   148     def cell_call(self, row, col, **kwargs):
   148         entity = self.entity(row, col)
   149         entity = self.entity(row, col)
   149         self.w(u'<h1>%s</h1>' % (self.req._('workflow for %s')
   150         self.w(u'<h1>%s</h1>' % (self.req._('workflow for %s')
   150                                  % display_name(self.req, entity.name)))
   151                                  % display_name(self.req, entity.name)))
   151         self.w(u'<img src="%s" alt="%s"/>' % (
   152         self.w(u'<img src="%s" alt="%s"/>' % (
   154 
   155 
   155 
   156 
   156 class WorkflowDotPropsHandler(object):
   157 class WorkflowDotPropsHandler(object):
   157     def __init__(self, req):
   158     def __init__(self, req):
   158         self._ = req._
   159         self._ = req._
   159         
   160 
   160     def node_properties(self, stateortransition):
   161     def node_properties(self, stateortransition):
   161         """return default DOT drawing options for a state or transition"""
   162         """return default DOT drawing options for a state or transition"""
   162         props = {'label': stateortransition.name, 
   163         props = {'label': stateortransition.name,
   163                  'fontname': 'Courier'}
   164                  'fontname': 'Courier'}
   164         if hasattr(stateortransition, 'state_of'):
   165         if hasattr(stateortransition, 'state_of'):
   165             props['shape'] = 'box'
   166             props['shape'] = 'box'
   166             props['style'] = 'filled'
   167             props['style'] = 'filled'
   167             if stateortransition.reverse_initial_state:
   168             if stateortransition.reverse_initial_state:
   177             if tr.condition:
   178             if tr.condition:
   178                 descr.append('%s %s'% (self._('condition:'), tr.condition))
   179                 descr.append('%s %s'% (self._('condition:'), tr.condition))
   179             if descr:
   180             if descr:
   180                 props['label'] += escape('\n'.join(descr))
   181                 props['label'] += escape('\n'.join(descr))
   181         return props
   182         return props
   182     
   183 
   183     def edge_properties(self, transition, fromstate, tostate):
   184     def edge_properties(self, transition, fromstate, tostate):
   184         return {'label': '', 'dir': 'forward',
   185         return {'label': '', 'dir': 'forward',
   185                 'color': 'black', 'style': 'filled'}
   186                 'color': 'black', 'style': 'filled'}
   186 
   187 
   187 
   188 
   191 
   192 
   192     def nodes(self):
   193     def nodes(self):
   193         for state in self.entity.reverse_state_of:
   194         for state in self.entity.reverse_state_of:
   194             state.complete()
   195             state.complete()
   195             yield state.eid, state
   196             yield state.eid, state
   196             
   197 
   197         for transition in self.entity.reverse_transition_of:
   198         for transition in self.entity.reverse_transition_of:
   198             transition.complete()
   199             transition.complete()
   199             yield transition.eid, transition
   200             yield transition.eid, transition
   200             
   201 
   201     def edges(self):
   202     def edges(self):
   202         for transition in self.entity.reverse_transition_of:
   203         for transition in self.entity.reverse_transition_of:
   203             for incomingstate in transition.reverse_allowed_transition:
   204             for incomingstate in transition.reverse_allowed_transition:
   204                 yield incomingstate.eid, transition.eid, transition
   205                 yield incomingstate.eid, transition.eid, transition
   205             yield transition.eid, transition.destination().eid, transition
   206             yield transition.eid, transition.destination().eid, transition
   207 
   208 
   208 class CWETypeWorkflowImageView(TmpFileViewMixin, view.EntityView):
   209 class CWETypeWorkflowImageView(TmpFileViewMixin, view.EntityView):
   209     id = 'ewfgraph'
   210     id = 'ewfgraph'
   210     content_type = 'image/png'
   211     content_type = 'image/png'
   211     __select__ = implements('CWEType')
   212     __select__ = implements('CWEType')
   212     
   213 
   213     def _generate(self, tmpfile):
   214     def _generate(self, tmpfile):
   214         """display schema information for an entity"""
   215         """display schema information for an entity"""
   215         entity = self.entity(self.row, self.col)
   216         entity = self.entity(self.row, self.col)
   216         visitor = WorkflowVisitor(entity)
   217         visitor = WorkflowVisitor(entity)
   217         prophdlr = WorkflowDotPropsHandler(self.req)
   218         prophdlr = WorkflowDotPropsHandler(self.req)