31 from logilab.common.graph import escape, GraphGenerator, DotBackend |
31 from logilab.common.graph import escape, GraphGenerator, DotBackend |
32 |
32 |
33 from cubicweb import Unauthorized, view |
33 from cubicweb import Unauthorized, view |
34 from cubicweb.selectors import (implements, has_related_entities, one_line_rset, |
34 from cubicweb.selectors import (implements, has_related_entities, one_line_rset, |
35 relation_possible, match_form_params, |
35 relation_possible, match_form_params, |
36 implements, score_entity) |
36 implements, score_entity, adaptable) |
37 from cubicweb.interfaces import IWorkflowable |
|
38 from cubicweb.view import EntityView |
37 from cubicweb.view import EntityView |
39 from cubicweb.schema import display_name |
38 from cubicweb.schema import display_name |
40 from cubicweb.web import uicfg, stdmsgs, action, component, form, action |
39 from cubicweb.web import uicfg, stdmsgs, action, component, form, action |
41 from cubicweb.web import formfields as ff, formwidgets as fwdgs |
40 from cubicweb.web import formfields as ff, formwidgets as fwdgs |
42 from cubicweb.web.views import TmpFileViewMixin, forms, primary, autoform |
41 from cubicweb.web.views import TmpFileViewMixin |
|
42 from cubicweb.web.views import forms, primary, autoform, ibreadcrumbs |
43 from cubicweb.web.views.tabs import TabbedPrimaryView, PrimaryTab |
43 from cubicweb.web.views.tabs import TabbedPrimaryView, PrimaryTab |
44 |
44 |
45 _pvs = uicfg.primaryview_section |
45 _pvs = uicfg.primaryview_section |
46 _pvs.tag_subject_of(('Workflow', 'initial_state', '*'), 'hidden') |
46 _pvs.tag_subject_of(('Workflow', 'initial_state', '*'), 'hidden') |
47 _pvs.tag_object_of(('*', 'state_of', 'Workflow'), 'hidden') |
47 _pvs.tag_object_of(('*', 'state_of', 'Workflow'), 'hidden') |
87 |
87 |
88 |
88 |
89 class ChangeStateFormView(form.FormViewMixIn, view.EntityView): |
89 class ChangeStateFormView(form.FormViewMixIn, view.EntityView): |
90 __regid__ = 'statuschange' |
90 __regid__ = 'statuschange' |
91 title = _('status change') |
91 title = _('status change') |
92 __select__ = (one_line_rset() & implements(IWorkflowable) |
92 __select__ = (one_line_rset() |
93 & match_form_params('treid')) |
93 & match_form_params('treid') |
|
94 & adaptable('IWorkflowable')) |
94 |
95 |
95 def cell_call(self, row, col): |
96 def cell_call(self, row, col): |
96 entity = self.cw_rset.get_entity(row, col) |
97 entity = self.cw_rset.get_entity(row, col) |
97 transition = self._cw.entity_from_eid(self._cw.form['treid']) |
98 transition = self._cw.entity_from_eid(self._cw.form['treid']) |
98 form = self.get_form(entity, transition) |
99 form = self.get_form(entity, transition) |
99 self.w(u'<h4>%s %s</h4>\n' % (self._cw._(transition.name), |
100 self.w(u'<h4>%s %s</h4>\n' % (self._cw._(transition.name), |
100 entity.view('oneline'))) |
101 entity.view('oneline'))) |
101 msg = self._cw._('status will change from %(st1)s to %(st2)s') % { |
102 msg = self._cw._('status will change from %(st1)s to %(st2)s') % { |
102 'st1': entity.printable_state, |
103 'st1': entity.cw_adapt_to('IWorkflowable').printable_state, |
103 'st2': self._cw._(transition.destination(entity).name)} |
104 'st2': self._cw._(transition.destination(entity).name)} |
104 self.w(u'<p>%s</p>\n' % msg) |
105 self.w(u'<p>%s</p>\n' % msg) |
105 self.w(form.render()) |
106 self.w(form.render()) |
106 |
107 |
107 def redirectpath(self, entity): |
108 def redirectpath(self, entity): |
126 |
127 |
127 |
128 |
128 class WFHistoryView(EntityView): |
129 class WFHistoryView(EntityView): |
129 __regid__ = 'wfhistory' |
130 __regid__ = 'wfhistory' |
130 __select__ = relation_possible('wf_info_for', role='object') & \ |
131 __select__ = relation_possible('wf_info_for', role='object') & \ |
131 score_entity(lambda x: x.workflow_history) |
132 score_entity(lambda x: x.cw_adapt_to('IWorkflowable').workflow_history) |
132 |
133 |
133 title = _('Workflow history') |
134 title = _('Workflow history') |
134 |
135 |
135 def cell_call(self, row, col, view=None): |
136 def cell_call(self, row, col, view=None): |
136 _ = self._cw._ |
137 _ = self._cw._ |
181 submenu = _('workflow') |
182 submenu = _('workflow') |
182 order = 10 |
183 order = 10 |
183 |
184 |
184 def fill_menu(self, box, menu): |
185 def fill_menu(self, box, menu): |
185 entity = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0) |
186 entity = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0) |
186 menu.label = u'%s: %s' % (self._cw._('state'), entity.printable_state) |
187 menu.label = u'%s: %s' % (self._cw._('state'), |
|
188 entity.cw_adapt_to('IWorkflowable').printable_state) |
187 menu.append_anyway = True |
189 menu.append_anyway = True |
188 super(WorkflowActions, self).fill_menu(box, menu) |
190 super(WorkflowActions, self).fill_menu(box, menu) |
189 |
191 |
190 def actual_actions(self): |
192 def actual_actions(self): |
191 entity = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0) |
193 entity = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0) |
|
194 iworkflowable = entity.cw_adapt_to('IWorkflowable') |
192 hastr = False |
195 hastr = False |
193 for tr in entity.possible_transitions(): |
196 for tr in iworkflowable.possible_transitions(): |
194 url = entity.absolute_url(vid='statuschange', treid=tr.eid) |
197 url = entity.absolute_url(vid='statuschange', treid=tr.eid) |
195 yield self.build_action(self._cw._(tr.name), url) |
198 yield self.build_action(self._cw._(tr.name), url) |
196 hastr = True |
199 hastr = True |
197 # don't propose to see wf if user can't pass any transition |
200 # don't propose to see wf if user can't pass any transition |
198 if hastr: |
201 if hastr: |
199 wfurl = entity.current_workflow.absolute_url() |
202 wfurl = iworkflowable.current_workflow.absolute_url() |
200 yield self.build_action(self._cw._('view workflow'), wfurl) |
203 yield self.build_action(self._cw._('view workflow'), wfurl) |
201 if entity.workflow_history: |
204 if iworkflowable.workflow_history: |
202 wfurl = entity.absolute_url(vid='wfhistory') |
205 wfurl = entity.absolute_url(vid='wfhistory') |
203 yield self.build_action(self._cw._('view history'), wfurl) |
206 yield self.build_action(self._cw._('view history'), wfurl) |
204 |
207 |
205 |
208 |
206 # workflow entity types views ################################################## |
209 # workflow entity types views ################################################## |
343 eids = self.edited_entity.linked_to('state_of', 'subject') |
346 eids = self.edited_entity.linked_to('state_of', 'subject') |
344 if eids: |
347 if eids: |
345 return workflow_items_for_relation(self._cw, eids[0], 'transition_of', |
348 return workflow_items_for_relation(self._cw, eids[0], 'transition_of', |
346 'allowed_transition') |
349 'allowed_transition') |
347 return [] |
350 return [] |
|
351 |
|
352 class WorkflowIBreadCrumbsAdapter(ibreadcrumbs.IBreadCrumbsAdapter): |
|
353 __select__ = implements('Workflow') |
|
354 # XXX what if workflow of multiple types? |
|
355 def parent_entity(self): |
|
356 return self.entity.workflow_of and self.entity.workflow_of[0] or None |
|
357 |
|
358 class WorkflowItemIBreadCrumbsAdapter(ibreadcrumbs.IBreadCrumbsAdapter): |
|
359 __select__ = implements('BaseTransition', 'State') |
|
360 def parent_entity(self): |
|
361 return self.entity.workflow |
|
362 |
|
363 class TransitionItemIBreadCrumbsAdapter(ibreadcrumbs.IBreadCrumbsAdapter): |
|
364 __select__ = implements('SubWorkflowExitPoint') |
|
365 def parent_entity(self): |
|
366 return self.entity.reverse_subworkflow_exit[0] |
|
367 |
|
368 class TrInfoIBreadCrumbsAdapter(ibreadcrumbs.IBreadCrumbsAdapter): |
|
369 __select__ = implements('TrInfo') |
|
370 def parent_entity(self): |
|
371 return self.entity.for_entity |
348 |
372 |
349 |
373 |
350 # workflow images ############################################################## |
374 # workflow images ############################################################## |
351 |
375 |
352 class WorkflowDotPropsHandler(object): |
376 class WorkflowDotPropsHandler(object): |