23 |
23 |
24 |
24 |
25 from cubicweb import _ |
25 from cubicweb import _ |
26 |
26 |
27 import os |
27 import os |
28 from warnings import warn |
|
29 |
28 |
30 from six import add_metaclass |
29 from six import add_metaclass |
31 |
30 |
32 from logilab.mtconverter import xml_escape |
31 from logilab.mtconverter import xml_escape |
33 from logilab.common.graph import escape |
|
34 from logilab.common.deprecation import class_deprecated |
32 from logilab.common.deprecation import class_deprecated |
35 |
33 |
36 from cubicweb import Unauthorized |
34 from cubicweb import Unauthorized |
37 from cubicweb.predicates import (has_related_entities, one_line_rset, |
35 from cubicweb.predicates import (one_line_rset, |
38 relation_possible, match_form_params, |
36 relation_possible, match_form_params, |
39 score_entity, is_instance, adaptable) |
37 score_entity, is_instance, adaptable) |
40 from cubicweb.view import EntityView |
38 from cubicweb.view import EntityView |
41 from cubicweb.schema import display_name |
39 from cubicweb.web import stdmsgs, action, component, form |
42 from cubicweb.web import stdmsgs, action, component, form, action |
40 from cubicweb.web import formwidgets as fwdgs |
43 from cubicweb.web import formfields as ff, formwidgets as fwdgs |
|
44 from cubicweb.web.views import TmpFileViewMixin |
41 from cubicweb.web.views import TmpFileViewMixin |
45 from cubicweb.web.views import uicfg, forms, primary, ibreadcrumbs |
42 from cubicweb.web.views import uicfg, forms, ibreadcrumbs |
46 from cubicweb.web.views.tabs import TabbedPrimaryView, PrimaryTab |
43 from cubicweb.web.views.tabs import TabbedPrimaryView, PrimaryTab |
47 from cubicweb.web.views.dotgraphview import DotGraphView, DotPropsHandler |
44 from cubicweb.web.views.dotgraphview import DotGraphView, DotPropsHandler |
48 |
45 |
49 _pvs = uicfg.primaryview_section |
46 _pvs = uicfg.primaryview_section |
50 _pvs.tag_subject_of(('Workflow', 'initial_state', '*'), 'hidden') |
47 _pvs.tag_subject_of(('Workflow', 'initial_state', '*'), 'hidden') |
75 _abaa.tag_object_of(('WorkflowTransition', 'transition_of', 'Workflow'), True) |
72 _abaa.tag_object_of(('WorkflowTransition', 'transition_of', 'Workflow'), True) |
76 |
73 |
77 _afs = uicfg.autoform_section |
74 _afs = uicfg.autoform_section |
78 _affk = uicfg.autoform_field_kwargs |
75 _affk = uicfg.autoform_field_kwargs |
79 |
76 |
|
77 |
80 # IWorkflowable views ######################################################### |
78 # IWorkflowable views ######################################################### |
81 |
79 |
82 class ChangeStateForm(forms.CompositeEntityForm): |
80 class ChangeStateForm(forms.CompositeEntityForm): |
83 # set dom id to ensure there is no conflict with edition form (see |
81 # set dom id to ensure there is no conflict with edition form (see |
84 # session_key() implementation) |
82 # session_key() implementation) |
85 __regid__ = domid = 'changestate' |
83 __regid__ = domid = 'changestate' |
86 |
84 |
87 form_renderer_id = 'base' # don't want EntityFormRenderer |
85 form_renderer_id = 'base' # don't want EntityFormRenderer |
88 form_buttons = [fwdgs.SubmitButton(), |
86 form_buttons = [fwdgs.SubmitButton(), |
89 fwdgs.Button(stdmsgs.BUTTON_CANCEL, |
87 fwdgs.Button(stdmsgs.BUTTON_CANCEL, |
90 {'class': fwdgs.Button.css_class + ' cwjs-edition-cancel'})] |
88 {'class': fwdgs.Button.css_class + ' cwjs-edition-cancel'})] |
91 |
89 |
92 |
90 |
236 _abaa.tag_object_of(('State', 'state_of', 'Workflow'), True) |
235 _abaa.tag_object_of(('State', 'state_of', 'Workflow'), True) |
237 _abaa.tag_object_of(('BaseTransition', 'transition_of', 'Workflow'), False) |
236 _abaa.tag_object_of(('BaseTransition', 'transition_of', 'Workflow'), False) |
238 _abaa.tag_object_of(('Transition', 'transition_of', 'Workflow'), True) |
237 _abaa.tag_object_of(('Transition', 'transition_of', 'Workflow'), True) |
239 _abaa.tag_object_of(('WorkflowTransition', 'transition_of', 'Workflow'), True) |
238 _abaa.tag_object_of(('WorkflowTransition', 'transition_of', 'Workflow'), True) |
240 |
239 |
|
240 |
241 class WorkflowPrimaryView(TabbedPrimaryView): |
241 class WorkflowPrimaryView(TabbedPrimaryView): |
242 __select__ = is_instance('Workflow') |
242 __select__ = is_instance('Workflow') |
243 tabs = [ _('wf_tab_info'), _('wfgraph'),] |
243 tabs = [_('wf_tab_info'), _('wfgraph')] |
244 default_tab = 'wf_tab_info' |
244 default_tab = 'wf_tab_info' |
245 |
245 |
246 |
246 |
247 class StateInContextView(EntityView): |
247 class StateInContextView(EntityView): |
248 """convenience trick, State's incontext view should not be clickable""" |
248 """convenience trick, State's incontext view should not be clickable""" |
250 __select__ = is_instance('State') |
250 __select__ = is_instance('State') |
251 |
251 |
252 def cell_call(self, row, col): |
252 def cell_call(self, row, col): |
253 self.w(xml_escape(self._cw.view('textincontext', self.cw_rset, |
253 self.w(xml_escape(self._cw.view('textincontext', self.cw_rset, |
254 row=row, col=col))) |
254 row=row, col=col))) |
|
255 |
255 |
256 |
256 class WorkflowTabTextView(PrimaryTab): |
257 class WorkflowTabTextView(PrimaryTab): |
257 __regid__ = 'wf_tab_info' |
258 __regid__ = 'wf_tab_info' |
258 __select__ = PrimaryTab.__select__ & one_line_rset() & is_instance('Workflow') |
259 __select__ = PrimaryTab.__select__ & one_line_rset() & is_instance('Workflow') |
259 |
260 |
260 def render_entity_attributes(self, entity): |
261 def render_entity_attributes(self, entity): |
261 _ = self._cw._ |
262 _ = self._cw._ |
262 self.w(u'<div>%s</div>' % (entity.printable_value('description'))) |
263 self.w(u'<div>%s</div>' % (entity.printable_value('description'))) |
263 self.w(u'<span>%s%s</span>' % (_("workflow_of").capitalize(), _(" :"))) |
264 self.w(u'<span>%s%s</span>' % (_("workflow_of").capitalize(), _(" :"))) |
264 html = [] |
265 html = [] |
265 for e in entity.workflow_of: |
266 for e in entity.workflow_of: |
266 view = e.view('outofcontext') |
267 view = e.view('outofcontext') |
267 if entity.eid == e.default_workflow[0].eid: |
268 if entity.eid == e.default_workflow[0].eid: |
268 view += u' <span>[%s]</span>' % _('default_workflow') |
269 view += u' <span>[%s]</span>' % _('default_workflow') |
269 html.append(view) |
270 html.append(view) |
270 self.w(', '.join(v for v in html)) |
271 self.w(', '.join(v for v in html)) |
271 self.w(u'<h2>%s</h2>' % _("Transition_plural")) |
272 self.w(u'<h2>%s</h2>' % _("Transition_plural")) |
272 rset = self._cw.execute( |
273 rset = self._cw.execute( |
273 'Any T,T,DS,T,TT ORDERBY TN WHERE T transition_of WF, WF eid %(x)s,' |
274 'Any T,T,DS,T,TT ORDERBY TN WHERE T transition_of WF, WF eid %(x)s,' |
274 'T type TT, T name TN, T destination_state DS?', {'x': entity.eid}) |
275 'T type TT, T name TN, T destination_state DS?', {'x': entity.eid}) |
275 self.wview('table', rset, 'null', |
276 self.wview('table', rset, 'null', |
276 cellvids={ 1: 'trfromstates', 2: 'outofcontext', 3:'trsecurity',}, |
277 cellvids={1: 'trfromstates', 2: 'outofcontext', 3: 'trsecurity'}, |
277 headers = (_('Transition'), _('from_state'), |
278 headers=(_('Transition'), _('from_state'), |
278 _('to_state'), _('permissions'), _('type') ), |
279 _('to_state'), _('permissions'), _('type'))) |
279 ) |
|
280 |
280 |
281 |
281 |
282 class TransitionSecurityTextView(EntityView): |
282 class TransitionSecurityTextView(EntityView): |
283 __regid__ = 'trsecurity' |
283 __regid__ = 'trsecurity' |
284 __select__ = is_instance('Transition') |
284 __select__ = is_instance('Transition') |
291 (_('groups'), _(" :"), |
291 (_('groups'), _(" :"), |
292 u', '.join((g.view('incontext') for g |
292 u', '.join((g.view('incontext') for g |
293 in entity.require_group)))) |
293 in entity.require_group)))) |
294 if entity.condition: |
294 if entity.condition: |
295 self.w(u'<div>%s%s %s</div>' % |
295 self.w(u'<div>%s%s %s</div>' % |
296 ( _('conditions'), _(" :"), |
296 (_('conditions'), _(" :"), |
297 u'<br/>'.join((e.dc_title() for e |
297 u'<br/>'.join((e.dc_title() for e in entity.condition)))) |
298 in entity.condition)))) |
298 |
299 |
299 |
300 class TransitionAllowedTextView(EntityView): |
300 class TransitionAllowedTextView(EntityView): |
301 __regid__ = 'trfromstates' |
301 __regid__ = 'trfromstates' |
302 __select__ = is_instance('Transition') |
302 __select__ = is_instance('Transition') |
303 |
303 |
315 param = 'toeid' if field.role == 'subject' else 'fromeid' |
315 param = 'toeid' if field.role == 'subject' else 'fromeid' |
316 return sorted((e.view('combobox'), unicode(e.eid)) |
316 return sorted((e.view('combobox'), unicode(e.eid)) |
317 for e in getattr(wf, 'reverse_%s' % wfrelation) |
317 for e in getattr(wf, 'reverse_%s' % wfrelation) |
318 if rschema.has_perm(req, 'add', **{param: e.eid})) |
318 if rschema.has_perm(req, 'add', **{param: e.eid})) |
319 |
319 |
|
320 |
320 # TrInfo |
321 # TrInfo |
321 _afs.tag_subject_of(('TrInfo', 'to_state', '*'), 'main', 'hidden') |
322 _afs.tag_subject_of(('TrInfo', 'to_state', '*'), 'main', 'hidden') |
322 _afs.tag_subject_of(('TrInfo', 'from_state', '*'), 'main', 'hidden') |
323 _afs.tag_subject_of(('TrInfo', 'from_state', '*'), 'main', 'hidden') |
323 _afs.tag_attribute(('TrInfo', 'tr_count'), 'main', 'hidden') |
324 _afs.tag_attribute(('TrInfo', 'tr_count'), 'main', 'hidden') |
|
325 |
324 |
326 |
325 # BaseTransition |
327 # BaseTransition |
326 # XXX * allowed_transition BaseTransition |
328 # XXX * allowed_transition BaseTransition |
327 # XXX BaseTransition destination_state * |
329 # XXX BaseTransition destination_state * |
328 |
330 |
335 if not eids: |
337 if not eids: |
336 return [] |
338 return [] |
337 wfeid = eids[0] |
339 wfeid = eids[0] |
338 return _wf_items_for_relation(form._cw, wfeid, 'state_of', field) |
340 return _wf_items_for_relation(form._cw, wfeid, 'state_of', field) |
339 |
341 |
|
342 |
340 _afs.tag_subject_of(('*', 'destination_state', '*'), 'main', 'attributes') |
343 _afs.tag_subject_of(('*', 'destination_state', '*'), 'main', 'attributes') |
341 _affk.tag_subject_of(('*', 'destination_state', '*'), |
344 _affk.tag_subject_of(('*', 'destination_state', '*'), |
342 {'choices': transition_states_vocabulary}) |
345 {'choices': transition_states_vocabulary}) |
343 _afs.tag_object_of(('*', 'allowed_transition', '*'), 'main', 'attributes') |
346 _afs.tag_object_of(('*', 'allowed_transition', '*'), 'main', 'attributes') |
344 _affk.tag_object_of(('*', 'allowed_transition', '*'), |
347 _affk.tag_object_of(('*', 'allowed_transition', '*'), |
345 {'choices': transition_states_vocabulary}) |
348 {'choices': transition_states_vocabulary}) |
|
349 |
346 |
350 |
347 # State |
351 # State |
348 |
352 |
349 def state_transitions_vocabulary(form, field): |
353 def state_transitions_vocabulary(form, field): |
350 entity = form.edited_entity |
354 entity = form.edited_entity |
351 if entity.has_eid(): |
355 if entity.has_eid(): |
352 wfeid = entity.state_of[0].eid |
356 wfeid = entity.state_of[0].eid |
353 else : |
357 else: |
354 eids = form.linked_to.get(('state_of', 'subject')) |
358 eids = form.linked_to.get(('state_of', 'subject')) |
355 if not eids: |
359 if not eids: |
356 return [] |
360 return [] |
357 wfeid = eids[0] |
361 wfeid = eids[0] |
358 return _wf_items_for_relation(form._cw, wfeid, 'transition_of', field) |
362 return _wf_items_for_relation(form._cw, wfeid, 'transition_of', field) |
359 |
363 |
|
364 |
360 _afs.tag_subject_of(('State', 'allowed_transition', '*'), 'main', 'attributes') |
365 _afs.tag_subject_of(('State', 'allowed_transition', '*'), 'main', 'attributes') |
361 _affk.tag_subject_of(('State', 'allowed_transition', '*'), |
366 _affk.tag_subject_of(('State', 'allowed_transition', '*'), |
362 {'choices': state_transitions_vocabulary}) |
367 {'choices': state_transitions_vocabulary}) |
363 |
368 |
364 |
369 |
365 # adaptaters ################################################################### |
370 # adaptaters ################################################################### |
366 |
371 |
367 class WorkflowIBreadCrumbsAdapter(ibreadcrumbs.IBreadCrumbsAdapter): |
372 class WorkflowIBreadCrumbsAdapter(ibreadcrumbs.IBreadCrumbsAdapter): |
368 __select__ = is_instance('Workflow') |
373 __select__ = is_instance('Workflow') |
|
374 |
369 # XXX what if workflow of multiple types? |
375 # XXX what if workflow of multiple types? |
370 def parent_entity(self): |
376 def parent_entity(self): |
371 return self.entity.workflow_of and self.entity.workflow_of[0] or None |
377 return self.entity.workflow_of and self.entity.workflow_of[0] or None |
372 |
378 |
|
379 |
373 class WorkflowItemIBreadCrumbsAdapter(ibreadcrumbs.IBreadCrumbsAdapter): |
380 class WorkflowItemIBreadCrumbsAdapter(ibreadcrumbs.IBreadCrumbsAdapter): |
374 __select__ = is_instance('BaseTransition', 'State') |
381 __select__ = is_instance('BaseTransition', 'State') |
|
382 |
375 def parent_entity(self): |
383 def parent_entity(self): |
376 return self.entity.workflow |
384 return self.entity.workflow |
377 |
385 |
|
386 |
378 class TransitionItemIBreadCrumbsAdapter(ibreadcrumbs.IBreadCrumbsAdapter): |
387 class TransitionItemIBreadCrumbsAdapter(ibreadcrumbs.IBreadCrumbsAdapter): |
379 __select__ = is_instance('SubWorkflowExitPoint') |
388 __select__ = is_instance('SubWorkflowExitPoint') |
|
389 |
380 def parent_entity(self): |
390 def parent_entity(self): |
381 return self.entity.reverse_subworkflow_exit[0] |
391 return self.entity.reverse_subworkflow_exit[0] |
382 |
392 |
|
393 |
383 class TrInfoIBreadCrumbsAdapter(ibreadcrumbs.IBreadCrumbsAdapter): |
394 class TrInfoIBreadCrumbsAdapter(ibreadcrumbs.IBreadCrumbsAdapter): |
384 __select__ = is_instance('TrInfo') |
395 __select__ = is_instance('TrInfo') |
|
396 |
385 def parent_entity(self): |
397 def parent_entity(self): |
386 return self.entity.for_entity |
398 return self.entity.for_entity |
387 |
399 |
388 |
400 |
389 # workflow images ############################################################## |
401 # workflow images ############################################################## |
420 for incomingstate in transition.reverse_allowed_transition: |
432 for incomingstate in transition.reverse_allowed_transition: |
421 yield incomingstate.eid, transition.eid, transition |
433 yield incomingstate.eid, transition.eid, transition |
422 for outgoingstate in transition.potential_destinations(): |
434 for outgoingstate in transition.potential_destinations(): |
423 yield transition.eid, outgoingstate.eid, transition |
435 yield transition.eid, outgoingstate.eid, transition |
424 |
436 |
|
437 |
425 class WorkflowGraphView(DotGraphView): |
438 class WorkflowGraphView(DotGraphView): |
426 __regid__ = 'wfgraph' |
439 __regid__ = 'wfgraph' |
427 __select__ = EntityView.__select__ & one_line_rset() & is_instance('Workflow') |
440 __select__ = EntityView.__select__ & one_line_rset() & is_instance('Workflow') |
428 |
441 |
429 def build_visitor(self, entity): |
442 def build_visitor(self, entity): |