workflows: add new edit modes (single, partial) (#41470)

This commit is contained in:
Frédéric Péters 2023-01-21 18:30:27 +01:00 committed by Gitea
parent 6523d409bd
commit 0fdd529074
4 changed files with 136 additions and 5 deletions

View File

@ -10281,3 +10281,80 @@ def test_form_edit_with_category(pub):
assert 'wfedit' in resp.location
resp = resp.follow()
assert 'f1' in resp.form.fields
def test_form_edit_single_page(pub):
user = create_user(pub)
workflow = Workflow(name='test')
st1 = workflow.add_status('Status1', 'st1')
editable = st1.add_action('editable', id='_editable')
editable.by = ['_submitter', '_receiver']
workflow.store()
formdef = create_formdef()
formdef.data_class().wipe()
formdef.fields = [
fields.PageField(id='1', label='1st page', type='page'),
fields.StringField(id='2', label='field1', type='string'),
fields.PageField(id='3', label='2nd page', type='page'),
fields.StringField(id='4', label='field2', type='string'),
fields.PageField(id='5', label='3rd page', type='page'),
fields.StringField(id='6', label='field3', type='string'),
]
formdef.workflow_id = workflow.id
formdef.store()
formdata = formdef.data_class()()
formdata.user_id = user.id
formdata.data = {'2': 'a', '4': 'b', '6': 'c'}
formdata.just_created()
formdata.store()
app = get_app(pub)
login(app, username='foo', password='foo')
resp = app.get(formdata.get_url())
resp = resp.form.submit('button_editable').follow()
assert [x.text for x in resp.pyquery('#steps .label')] == ['1st page', '2nd page', '3rd page']
editable.operation_mode = 'single'
editable.page_identifier = 'plop'
workflow.store()
# unknown page identifier, a 404 is raised
resp = app.get(formdata.get_url())
resp = resp.form.submit('button_editable').follow(status=404)
# add identifier to second page, and edit it
formdef.fields[2].varname = 'plop'
formdef.store()
resp = app.get(formdata.get_url())
resp = resp.form.submit('button_editable').follow()
assert [x.text for x in resp.pyquery('#steps .label')] == ['2nd page']
resp.form['f4'] = 'changed'
assert [x.text for x in resp.pyquery('.buttons button')] == ['Save Changes', 'Cancel']
resp = resp.form.submit('submit')
formdata.refresh_from_storage()
assert formdata.data == {'2': 'a', '4': 'changed', '6': 'c'}
# change action to edit all pages starting at page 2
editable.operation_mode = 'partial'
workflow.store()
resp = app.get(formdata.get_url())
resp = resp.form.submit('button_editable').follow()
assert [x.text for x in resp.pyquery('#steps .label')] == ['2nd page', '3rd page']
resp.form['f4'] = 'other change'
assert [x.text for x in resp.pyquery('.buttons button')] == ['Next', 'Cancel']
resp = resp.form.submit('submit')
assert [x.text for x in resp.pyquery('.buttons button')] == ['Save Changes', 'Previous', 'Cancel']
resp = resp.form.submit('previous')
assert [x.text for x in resp.pyquery('.buttons button')] == ['Next', 'Cancel']
resp = resp.form.submit('submit')
resp.form['f6'] = 'last change'
assert [x.text for x in resp.pyquery('.buttons button')] == ['Save Changes', 'Previous', 'Cancel']
resp = resp.form.submit('submit')
formdata.refresh_from_storage()
assert formdata.data == {'2': 'a', '4': 'other change', '6': 'last change'}

View File

@ -1004,8 +1004,8 @@ class FormStatusPage(Directory, FormTemplateMixin):
f = self.form_page_class(self.formdef.url_name)
f.edit_mode = True
f.edited_data = self.filled
f.edit_action_id = action_id
f.action_url = 'wfedit-%s' % action_id
f.edit_action = item
f.action_url = 'wfedit-%s' % item.id
if get_request().is_in_backoffice():
get_session().mark_visited_object(self.filled)
get_response().breadcrumb = get_response().breadcrumb[:-1]

View File

@ -297,6 +297,7 @@ class FormPage(FormdefDirectoryBase, FormTemplateMixin):
self.code = TrackingCodesDirectory(self.formdef)
self.action_url = '.'
self.edit_mode = False
self.edit_action = None
self.on_validation_page = False
self.current_page = None
self.user = get_request().user
@ -960,6 +961,16 @@ class FormPage(FormdefDirectoryBase, FormTemplateMixin):
field_page = field
if field.is_visible(current_data, self.formdef):
pages.append(field)
if self.edit_mode and self.edit_action and self.edit_action.operation_mode in ('single', 'partial'):
edit_pages = []
for page in pages:
if self.edit_action.page_identifier == page.varname or edit_pages:
edit_pages.append(page)
if self.edit_action.operation_mode == 'single':
break
if not edit_pages:
raise errors.TraversalError()
pages = edit_pages
if not field_page: # form without page fields
pages = [None]
self._pages = pages
@ -1715,7 +1726,7 @@ class FormPage(FormdefDirectoryBase, FormTemplateMixin):
wf_status = self.edited_data.get_status()
url = None
for item in wf_status.items:
if item.id == self.edit_action_id:
if item.id == self.edit_action.id:
user = get_request().user
user_id = None
if user:

View File

@ -17,7 +17,13 @@
from quixote import get_publisher, get_request
from wcs.qommon import _
from wcs.qommon.form import SingleSelectWidget, StringWidget, WidgetList, WysiwygTextWidget
from wcs.qommon.form import (
RadiobuttonsWidget,
SingleSelectWidget,
StringWidget,
WidgetList,
WysiwygTextWidget,
)
from wcs.workflows import WorkflowStatusItem, register_item_class
@ -33,6 +39,8 @@ class EditableWorkflowStatusItem(WorkflowStatusItem):
status = None
label = None
backoffice_info_text = None
operation_mode = 'full' # or 'single' or 'partial'
page_identifier = None
def get_line_details(self):
if self.by:
@ -103,9 +111,44 @@ class EditableWorkflowStatusItem(WorkflowStatusItem):
title=_('Information Text for Backoffice'),
value=self.backoffice_info_text,
)
if 'operation_mode' in parameters:
form.add(
RadiobuttonsWidget,
'%soperation_mode' % prefix,
title=_('Operation Mode'),
options=[
('full', _('All pages'), 'full'),
('single', _('Single page'), 'single'),
('partial', _('From specific page'), 'partial'),
],
advanced=True,
value=self.operation_mode,
attrs={'data-dynamic-display-parent': 'true'},
extra_css_class='widget-inline-radio',
)
if 'page_identifier' in parameters:
form.add(
StringWidget,
'%spage_identifier' % prefix,
title=_('Page Identifier'),
value=self.page_identifier,
advanced=True,
attrs={
'data-dynamic-display-child-of': '%soperation_mode' % prefix,
'data-dynamic-display-value-in': 'single|partial',
},
)
def get_parameters(self):
return ('by', 'status', 'label', 'backoffice_info_text', 'condition')
return (
'by',
'status',
'label',
'backoffice_info_text',
'condition',
'operation_mode',
'page_identifier',
)
register_item_class(EditableWorkflowStatusItem)