backoffice: group adjacent block subfield columns (#78318) #893
|
@ -533,12 +533,22 @@ def test_backoffice_block_columns(pub):
|
|||
'Block / card field',
|
||||
'Anonymised',
|
||||
]
|
||||
# enable columns for subfields
|
||||
resp.forms['listing-settings']['8-123'].checked = True
|
||||
resp.forms['listing-settings']['8-456'].checked = True
|
||||
resp = resp.forms['listing-settings'].submit()
|
||||
assert '<th><span>Block / Test</span></th>' in resp
|
||||
assert '<th><span>Block / card field</span></th>' in resp
|
||||
assert resp.text.count('<tr') == 2
|
||||
# thead is now on two rows
|
||||
assert resp.pyquery('thead tr').length == 2
|
||||
assert [x.text_content() for x in resp.pyquery('thead tr:first-child th')] == [
|
||||
'',
|
||||
'Number',
|
||||
'Created',
|
||||
'Last Modified',
|
||||
'User Label',
|
||||
'Status',
|
||||
'Block',
|
||||
]
|
||||
assert [x.text_content() for x in resp.pyquery('thead tr:last-child th')] == ['Test', 'card field']
|
||||
assert '<td>blah</td>' in resp
|
||||
assert '<td>Foo Bar</td>' in resp
|
||||
|
||||
|
@ -561,8 +571,16 @@ def test_backoffice_block_columns(pub):
|
|||
resp.forms['listing-settings']['8-123'].checked = True
|
||||
resp.forms['listing-settings']['8-456'].checked = True
|
||||
resp = resp.forms['listing-settings'].submit()
|
||||
assert '<th data-field-sort-key="f8-123"><span>Block / Test</span></th>' in resp
|
||||
assert '<th data-field-sort-key="f8-456"><span>Block / card field</span></th>' in resp
|
||||
assert resp.pyquery('th[data-field-sort-key="f8-123"]').text() == 'Test'
|
||||
assert resp.pyquery('th[data-field-sort-key="f8-456"]').text() == 'card field'
|
||||
|
||||
# enable a single block subfield
|
||||
resp.forms['listing-settings']['8-123'].checked = False
|
||||
resp.forms['listing-settings']['8-456'].checked = True
|
||||
resp = resp.forms['listing-settings'].submit()
|
||||
# thead is now on a single row
|
||||
assert resp.pyquery('thead tr').length == 1
|
||||
assert resp.pyquery('th[data-field-sort-key="f8-456"]').text() == 'Block / card field'
|
||||
|
||||
|
||||
def test_backoffice_block_email_column(pub):
|
||||
|
|
|
@ -1148,12 +1148,15 @@ def test_backoffice_custom_view_columns(pub):
|
|||
|
||||
app = login(get_app(pub))
|
||||
resp = app.get('/backoffice/management/form-title/shared-custom-test-view/')
|
||||
assert '<span>Number</span></th>' in resp
|
||||
assert resp.pyquery('th').length == 2
|
||||
assert resp.pyquery('th').text().strip() == 'Number'
|
||||
|
||||
custom_view.columns = {'list': [{'id': 'unknown'}]}
|
||||
custom_view.store()
|
||||
resp = app.get('/backoffice/management/form-title/shared-custom-test-view/')
|
||||
assert '<th></th>' in resp # columns not found
|
||||
# columns not found
|
||||
assert resp.pyquery('th').length == 1
|
||||
assert not resp.pyquery('th').text()
|
||||
|
||||
|
||||
def test_backoffice_custom_view_sort_field(pub):
|
||||
|
|
|
@ -98,17 +98,52 @@ class FormDefUI:
|
|||
r += htmltext('</colgroup>')
|
||||
|
||||
r += htmltext('<thead><tr>')
|
||||
|
||||
# group adjacent same-block columns
|
||||
previous_block_subfield = None
|
||||
grouped_columns = []
|
||||
for f in fields:
|
||||
if getattr(f, 'block_field', None):
|
||||
if previous_block_subfield and f.block_field.id == previous_block_subfield.block_field.id:
|
||||
previous_block_subfield.include_block_label = False
|
||||
grouped_columns[-1]['count'] += 1
|
||||
f.include_block_label = False
|
||||
f.block_column = grouped_columns[-1]
|
||||
|
||||
else:
|
||||
grouped_columns.append({'label': f.block_field.label, 'count': 1})
|
||||
f.include_block_label = True
|
||||
f.block_column = grouped_columns[-1]
|
||||
previous_block_subfield = f
|
||||
else:
|
||||
previous_block_subfield = None
|
||||
grouped_columns.append({'count': 1})
|
||||
|
||||
thead_height = 1
|
||||
if any(x.get('count') > 1 for x in grouped_columns):
|
||||
# if there are adjacent same-block columns, the thead will have two rows
|
||||
thead_height = 2
|
||||
|
||||
if self.formdef.workflow.criticality_levels:
|
||||
r += htmltext(
|
||||
'<th class="criticality-level-cell" data-field-sort-key="criticality_level"><span></span></th>'
|
||||
f'<th rowspan="{thead_height}" class="criticality-level-cell" '
|
||||
'data-field-sort-key="criticality_level"><span></span></th>'
|
||||
)
|
||||
else:
|
||||
r += htmltext('<th></th>') # lock
|
||||
r += htmltext(f'<th rowspan="{thead_height}"></th>') # lock
|
||||
if include_checkboxes:
|
||||
r += htmltext('<th class="select"><input type="checkbox" id="top-select"/>')
|
||||
r += htmltext(
|
||||
f'<th rowspan="{thead_height}" class="select"><input type="checkbox" id="top-select"/>'
|
||||
)
|
||||
r += htmltext(
|
||||
' <span id="info-all-rows"><label><input type="checkbox" name="select[]" value="_all"/> %s</label></span></th>'
|
||||
) % _('Run selected action on all pages')
|
||||
|
||||
def get_column_title(label):
|
||||
if len(label) < 20:
|
||||
return htmltext('<span>%s</span>') % label
|
||||
else:
|
||||
return htmltext('<span title="%s">%s</span>') % (label, misc.ellipsize(label, 20))
|
||||
fpeters
commented
Petite refacto de ça vu qu'on va l'utiliser plusieurs fois. Petite refacto de ça vu qu'on va l'utiliser plusieurs fois.
|
||||
|
||||
for f in fields:
|
||||
if getattr(f, 'fake', False):
|
||||
field_sort_key = f.id
|
||||
|
@ -124,17 +159,40 @@ class FormDefUI:
|
|||
else:
|
||||
field_sort_key = 'f%s' % f.contextual_id
|
||||
|
||||
if field_sort_key:
|
||||
r += htmltext('<th data-field-sort-key="%s">') % field_sort_key
|
||||
else:
|
||||
r += htmltext('<th>')
|
||||
th_rowspan = f' rowspan="{thead_height}"' if thead_height > 1 else ''
|
||||
fpeters
commented
Quand il y a une hauteur à tenir, ajout d'un attribut rowspan. (ça aurait pu être rowspan="1" dans les autres cas mais ça fait des tests qui cherchaient juste qui échouent, autant s'éviter ça). Quand il y a une hauteur à tenir, ajout d'un attribut rowspan. (ça aurait pu être rowspan="1" dans les autres cas mais ça fait des tests qui cherchaient juste <th> qui échouent, autant s'éviter ça).
|
||||
if getattr(f, 'block_field', None):
|
||||
f.label = '%s / %s' % (f.block_field.label, f.label)
|
||||
if len(f.label) < 20:
|
||||
r += htmltext('<span>%s</span>') % f.label
|
||||
if f.include_block_label:
|
||||
# isolated block subfield column
|
||||
f.label = '%s / %s' % (f.block_field.label, f.label)
|
||||
fpeters
commented
Le comportement actuel, libellé avec bloc / champ. Le comportement actuel, libellé avec bloc / champ.
|
||||
else:
|
||||
# grouped subfields first row, block name
|
||||
if not f.block_column.get('seen'):
|
||||
f.block_column['seen'] = True
|
||||
r += htmltext(f'<th class="col-group" colspan="{f.block_column["count"]}">')
|
||||
r += get_column_title(f.block_field.label)
|
||||
fpeters
commented
Pour les colonnes groupées, si le th n'a pas encore été ajouté, on le met à la bonne largeur; sinon on zappe juste le champ, il apparaitra sur la deuxième ligne du thead. Pour les colonnes groupées, si le th n'a pas encore été ajouté, on le met à la bonne largeur; sinon on zappe juste le champ, il apparaitra sur la deuxième ligne du thead.
|
||||
r += htmltext('</th>')
|
||||
f.field_sort_key = field_sort_key
|
||||
continue
|
||||
|
||||
if field_sort_key:
|
||||
r += htmltext(f'<th{th_rowspan} data-field-sort-key="{field_sort_key}">')
|
||||
else:
|
||||
r += htmltext('<span title="%s">%s</span>') % (f.label, misc.ellipsize(f.label, 20))
|
||||
r += htmltext(f'<th{th_rowspan}>')
|
||||
r += get_column_title(f.label)
|
||||
r += htmltext('</th>')
|
||||
|
||||
if thead_height > 1:
|
||||
# add individual columns for grouped subfields
|
||||
r += htmltext('</tr><tr>')
|
||||
for f in fields:
|
||||
if getattr(f, 'block_field', None) and not f.include_block_label:
|
||||
if f.field_sort_key:
|
||||
fpeters
commented
Deuxième ligne du thead, on ajoute des colonnes pour les champs des blocs. Deuxième ligne du thead, on ajoute des colonnes pour les champs des blocs.
|
||||
r += htmltext(f'<th class="col-subfield" data-field-sort-key="{f.field_sort_key}">')
|
||||
else:
|
||||
r += htmltext('<th class="col-subfield">')
|
||||
r += get_column_title(f.label)
|
||||
r += htmltext('</th>')
|
||||
|
||||
r += htmltext('</tr></thead>')
|
||||
r += htmltext('<tbody>')
|
||||
r += htmltext(self.tbody(fields, items, url_action, include_checkboxes=include_checkboxes))
|
||||
|
|
|
@ -465,6 +465,16 @@ table.main td {
|
|||
|
||||
table.main th {
|
||||
cursor: pointer;
|
||||
&.col-group,
|
||||
&.col-subfield {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
&.col-group {
|
||||
background: #eee;
|
||||
border: 1px solid #aaa;
|
||||
border-width: 0px 2px;
|
||||
}
|
||||
}
|
||||
|
||||
table.main th.nosort {
|
||||
|
|
Loading…
Reference in New Issue
Si on est sur le cas de sous-champs de blocs qui se suivent, on n'inclut plus le libellé du bloc dans le libellé de la colonne, on incrément le nombre de colonnes qui seront réunies et on ajoute une référence à ces infos dans l'objet du champ, ça resservira plus tard.