general: expand blocks in form_details (#44804)
gitea/wcs/pipeline/head This commit looks good Details

This commit is contained in:
Frédéric Péters 2024-03-21 21:12:34 +01:00
parent aa070498e4
commit 0c7f2ea925
8 changed files with 73 additions and 79 deletions

View File

@ -1648,14 +1648,12 @@ def test_block_card_item_link(pub):
# check cards are links in backoffice
resp = app.get('/backoffice/management' + resp.request.path)
assert (
'<div class="value"><a href="http://example.net/backoffice/data/foo/%s/">card plop</a></div></div>'
% card.id
in resp
resp.pyquery('div.value > a[href="http://example.net/backoffice/data/foo/%s/"]' % card.id).text()
== 'card plop'
)
assert (
'<div class="value"><a href="http://example.net/backoffice/data/foo/%s/">card plop2</a></div></div>'
% card2.id
in resp
resp.pyquery('div.value > a[href="http://example.net/backoffice/data/foo/%s/"]' % card2.id).text()
== 'card plop2'
)

View File

@ -1741,10 +1741,10 @@ def test_block_subfields_display_locations(pub):
block = BlockDef()
block.name = 'foobar'
block.fields = [
fields.StringField(id='123', required=True, label='Test'),
fields.TitleField(id='234', label='Blah Title'),
fields.SubtitleField(id='345', label='Blah Subtitle'),
fields.CommentField(id='456', label='Blah Comment'),
fields.StringField(id='123', required=True, label='Test'),
]
block.store()
@ -1849,7 +1849,6 @@ def test_block_block_counter(pub):
block = BlockDef()
block.name = 'foobar'
block.fields = [
fields.StringField(id='123', required=True, label='Test'),
fields.TitleField(
id='234', label='Blah Title #{{ block_counter.index }} #{{ block_counter.index0 }}'
),
@ -1859,6 +1858,7 @@ def test_block_block_counter(pub):
fields.CommentField(
id='456', label='Blah Comment #{{ block_counter.index }} #{{ block_counter.index0 }}'
),
fields.StringField(id='123', required=True, label='Test'),
]
block.store()

View File

@ -97,7 +97,7 @@ def test_blocks_in_form_details(pub):
assert 'test1' not in details
assert 'test empty block' not in details
assert 'test2' in details
assert 'bar' in details
assert 'plop:\n foo\n' in details
def test_block_migrate(pub):

View File

@ -5619,7 +5619,9 @@ def test_rst_form_details_all_fields(pub):
assert '**Subtitle**\n\n' in rst
assert 'Text:\n para1\n para2' in rst
assert 'File:\n test.jpeg' in rst
assert 'Block Field:\n XfooY, Xfoo2Y' in rst
assert 'Block Field:\n' in rst
assert 'Test:\n foo\n' in rst
assert 'Test:\n foo2\n' in rst
assert 'Map:\n 2;4\n\n' in rst

View File

@ -491,8 +491,12 @@ def test_export_to_model_form_details_section(pub, filename):
assert '>2015-05-12<' in new_content
assert 'Invisible' not in new_content
assert new_content.count('/table:table-cell') == 8
assert 'XfooY, Xfoo2Y' in new_content
assert '>14.4<' in new_content
# block sub fields
assert '>foo<' in new_content
assert '>bar<' in new_content
assert '>foo2<' in new_content
assert '>bar2<' in new_content
if filename == 'template-form-details-no-styles.odt':
with open(formdata.evolution[0].parts[-1].get_file_path(), 'rb') as fd:

View File

@ -15,17 +15,13 @@
# along with this program; if not, see <http://www.gnu.org/licenses/>.
import copy
import xml.etree.ElementTree as ET
from django.utils.encoding import force_str
from quixote import get_publisher
from quixote.html import TemplateIO, htmltext
from wcs.blocks import BlockDef, BlockWidget
from wcs.qommon import _
from wcs.qommon.form import CheckboxWidget, IntWidget, SingleSelectWidget, StringWidget
from wcs.qommon.ods import NS as OD_NS
from wcs.qommon.ods import clean_text as od_clean_text
from .base import SetValueError, WidgetField
from .item import UnknownCardValueError
@ -200,67 +196,25 @@ class BlockField(WidgetField):
parts.append(self.block.get_display_value(subvalue) or '')
return ', '.join(parts)
def get_view_value(self, value, summary=False, include_unset_required_fields=False, **kwargs):
from wcs.workflows import template_on_formdata
if 'value_id' not in kwargs:
# when called from get_rst_view_value()
return str(value or '')
value = kwargs['value_id']
if value is None:
return ''
r = TemplateIO(html=True)
for i, row_value in enumerate(value['data']):
def get_value_details(self, formdata, value, include_unset_required_fields):
for i, row_value in enumerate((value or {}).get('data') or []):
try:
block = self.block
except KeyError:
# block was deleted, ignore
continue
context = block.get_substitution_counter_variables(i)
for field in block.fields:
if summary and not field.include_in_summary_page:
continue
if not hasattr(field, 'get_value_info'):
# inert field
if field.include_in_summary_page:
with get_publisher().substitutions.temporary_feed(context):
if field.key == 'title':
label = template_on_formdata(None, field.label, autoescape=False)
r += htmltext('<div class="title %s"><h3>%s</h3></div>') % (
field.extra_css_class or '',
label,
)
elif field.key == 'subtitle':
label = template_on_formdata(None, field.label, autoescape=False)
r += htmltext('<div class="subtitle %s"><h4>%s</h4></div>') % (
field.extra_css_class or '',
label,
)
elif field.key == 'comment':
r += htmltext(
'<div class="comment-field %s">%s</div>'
% (field.extra_css_class or '', field.get_text())
)
continue
css_classes = ['field', 'field-type-%s' % field.key]
if field.extra_css_class:
css_classes.append(field.extra_css_class)
sub_value, sub_value_details = field.get_value_info(row_value)
if sub_value is None and not (field.required and include_unset_required_fields):
continue
label_id = f'form-field-label-f{self.id}-r{i}-s{field.id}'
r += htmltext('<div class="%s">' % ' '.join(css_classes))
r += htmltext('<p id="%s" class="label">%s</p> ') % (label_id, field.label)
if sub_value is None:
r += htmltext('<div class="value"><i>%s</i></div>') % _('Not set')
else:
r += htmltext('<div class="value">')
kwargs = {'parent_field': self, 'parent_field_index': i, 'label_id': label_id}
kwargs.update(**sub_value_details)
r += field.get_view_value(sub_value, **kwargs)
r += htmltext('</div>')
r += htmltext('</div>\n')
return r.getvalue()
with get_publisher().substitutions.temporary_feed(context):
yield from formdata.get_summary_field_details(
fields=block.fields,
include_unset_required_fields=include_unset_required_fields,
data=row_value,
parent_field=self,
parent_field_index=i,
)
def get_view_value(self, value, summary=False, include_unset_required_fields=False, **kwargs):
return str(value or '')
def get_value_info(self, data):
value = data.get(self.id)
@ -338,11 +292,6 @@ class BlockField(WidgetField):
return {'data': result, 'schema': {x.id: x.key for x in self.block.fields}}
def get_opendocument_node_value(self, value, formdata=None, **kwargs):
node = ET.Element('{%s}span' % OD_NS['text'])
node.text = od_clean_text(force_str(value))
return node
def __getstate__(self):
# do not store _block cache
odict = super().__getstate__()

View File

@ -1755,10 +1755,20 @@ class FormData(StorableObject):
for field in self.formdef.fields:
field.feed_session(self.data.get(field.id), self.data.get('%s_display' % field.id))
def get_summary_field_details(self, fields=None, include_unset_required_fields=False):
def get_summary_field_details(
self,
fields=None,
include_unset_required_fields=False,
data=None,
parent_field=None,
parent_field_index=None,
):
if fields is None:
fields = self.formdef.fields
if data is None:
data = self.data
on_page = False
current_page_fields = []
pages = []
@ -1820,10 +1830,14 @@ class FormData(StorableObject):
if not f.include_in_summary_page:
continue
value, value_details = f.get_value_info(self.data)
value, value_details = f.get_value_info(data)
if value is None and not (f.required and include_unset_required_fields):
continue
if parent_field:
value_details['parent_field'] = parent_field
value_details['parent_field_index'] = parent_field_index
current_page_fields.append({'field': f, 'value': value, 'value_details': value_details})
has_contents_since_latest_subtitle = True
has_contents_since_latest_title = True
@ -1960,15 +1974,23 @@ class FormData(StorableObject):
)
def get_summary_display_actions(self, fields=None, form_url='', include_unset_required_fields=False):
from wcs.workflows import template_on_formdata
field_details = self.get_summary_field_details(
fields, include_unset_required_fields=include_unset_required_fields
)
yield from self.iter_summary_display_actions(
field_details,
form_url=form_url,
include_unset_required_fields=include_unset_required_fields,
)
def iter_summary_display_actions(self, field_details, form_url='', include_unset_required_fields=False):
from wcs.workflows import template_on_formdata
on_page = None
for field_value_info in field_details:
f = field_value_info['field']
parent_field = field_value_info.get('value_details', {}).get('parent_field')
parent_field_index = field_value_info.get('value_details', {}).get('parent_field_index')
if f.key == 'page':
if on_page:
yield {'action': 'close-page'}
@ -1995,6 +2017,8 @@ class FormData(StorableObject):
css_classes.append(f.extra_css_class)
css_classes = ' '.join(css_classes)
label_id = f'form-field-label-f{f.id}'
if parent_field:
label_id = f'form-field-label-f{parent_field.id}-r{parent_field_index}-s{f.id}'
yield {'action': 'open-field', 'css': css_classes}
if f.key == 'block' and f.label_display == 'subtitle':
yield {
@ -2015,6 +2039,19 @@ class FormData(StorableObject):
if value is None:
if not (f.key == 'block' and f.label_display == 'hidden'):
yield {'action': 'value', 'value': None}
elif f.key == 'block':
block_field_details = f.get_value_details(
formdata=self,
value=value_details.get('value_id'),
include_unset_required_fields=include_unset_required_fields,
)
yield {'action': 'open-block-value'}
yield from self.iter_summary_display_actions(
block_field_details,
form_url=form_url,
include_unset_required_fields=include_unset_required_fields,
)
yield {'action': 'close-block-value'}
else:
s = f.get_view_value(
value,

View File

@ -581,6 +581,10 @@ class FormStatusPage(Directory, FormTemplateMixin):
r += htmltext('<div class="page">')
r += htmltext('<h3>%s</h3>') % field_action['value']
r += htmltext('<div>')
elif field_action['action'] == 'open-block-value':
r += htmltext('<div class="value value--block">')
elif field_action['action'] == 'close-block-value':
r += htmltext('</div>')
elif field_action['action'] == 'title':
r += htmltext('<div class="title %s"><h3>%s</h3></div>') % (
field_action['css'],