misc: add support for dynamic views filtered on dates (#64991) #1175

Merged
fpeters merged 1 commits from wip/64991-dynamic-date-view into main 2024-03-15 07:21:22 +01:00
2 changed files with 98 additions and 8 deletions

View File

@ -1777,6 +1777,102 @@ def test_dynamic_item_field_from_custom_view_on_cards(pub, field_type):
assert logged_error.summary == '[DATASOURCE] Unknown custom view "as-data-source" for CardDef "items"'
def test_dynamic_date_field_from_custom_view_on_cards(pub):
pub.role_class.wipe()
pub.custom_view_class.wipe()
user = create_user(pub)
role = pub.role_class(name='xxx')
role.store()
user.roles = [role.id]
user.is_admin = True
user.store()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'test'
formdef.fields = []
formdef.store()
formdef.data_class().wipe()
CardDef.wipe()
carddef = CardDef()
carddef.name = 'items'
carddef.digest_templates = {'default': '{{form_var_attr}}'}
carddef.workflow_roles = {'_editor': user.roles[0]}
carddef.fields = [
fields.StringField(id='1', label='string', varname='attr'),
fields.DateField(id='2', label='date'),
]
carddef.store()
carddef.data_class().wipe()
for i, value in enumerate(['foo', 'bar', 'baz']):
carddata = carddef.data_class()()
carddata.data = {
'1': value,
'2': datetime.date(2024, 1, 1 + i).timetuple(),
}
carddata.just_created()
carddata.store()
# create custom view
app = login(get_app(pub), username='foo', password='foo')
resp = app.get('/backoffice/data/items/')
resp.forms['listing-settings']['filter-2'].checked = True
resp.forms['listing-settings']['filter-status'].checked = True
resp = resp.forms['listing-settings'].submit()
resp.forms['listing-settings']['filter'].value = 'recorded'
resp = resp.forms['listing-settings'].submit()
resp.forms['save-custom-view']['title'] = 'as data source'
resp.forms['save-custom-view']['visibility'] = 'datasource'
resp = resp.forms['save-custom-view'].submit().follow()
# make sure <input type=date> is not used, so a template can be entered
assert resp.pyquery('[name="filter-2-value"]')[0].attrib['type'] == 'text'
resp.forms['listing-settings']['filter-2-value'] = '{{ form_var_blah }}'
resp.forms['listing-settings']['filter-2-operator'].value = 'gte'
resp = resp.forms['listing-settings'].submit()
assert resp.forms['listing-settings']['filter-2-value'].value == '{{ form_var_blah }}'
assert resp.text.count('<tr') == 1 # thead only
# save custom view with filter
resp = resp.forms['save-custom-view'].submit().follow()
custom_view = pub.custom_view_class.select()[0]
# use custom view as source
ds = {'type': 'carddef:%s:%s' % (carddef.url_name, custom_view.slug)}
formdef.fields = [
fields.PageField(id='2', label='1st page'),
fields.ItemField(
id='0', label='item', varname='blah', items=['2023-01-02', '2024-01-02', '2025-01-02']
),
fields.ItemField(id='1', label='string', data_source=ds, display_disabled_items=True),
]
formdef.store()
resp = get_app(pub).get('/test/')
assert resp.form['f1'].options == [('', False, '---')]
resp.form['f0'] = '2024-01-02'
live_resp = app.post('/test/live?modified_field_id[]=0', params=resp.form.submit_fields())
assert live_resp.json['result']['1']['items'] == [
{'attr': 'bar', 'id': 2, 'text': 'bar'},
{'attr': 'baz', 'id': 3, 'text': 'baz'},
]
resp.form['f0'] = '2023-01-02'
live_resp = app.post('/test/live?modified_field_id[]=0', params=resp.form.submit_fields())
assert len(live_resp.json['result']['1']['items']) == 3
resp.form['f0'] = '2025-01-02'
live_resp = app.post('/test/live?modified_field_id[]=0', params=resp.form.submit_fields())
assert len(live_resp.json['result']['1']['items']) == 0
def test_dynamic_item_fields_from_custom_view_on_cards(pub):
pub.role_class.wipe()
pub.custom_view_class.wipe()

View File

@ -1454,18 +1454,12 @@ class FormPage(Directory, TempfileDirectoryMixin):
)
r += render_widget(widget, operators)
elif filter_field.key in ('string', 'text', 'email', 'numeric'):
elif filter_field.key in ('string', 'text', 'email', 'numeric', 'date'):
widget = StringWidget(
filter_field_key, title=filter_field.label, value=filter_field_value, render_br=False
)
r += render_widget(widget, operators)
elif filter_field.key == 'date':
widget = DateWidget(
filter_field_key, title=filter_field.label, value=filter_field_value, render_br=False
)
r += render_widget(widget, operators)
Review

Cette partie n'était plus effective avec l'ajout des opérateurs, le render_widget() appelle directement render_content(), qui ne passait pas par le gabarit HTML du widget, et fournissait déjà un input type="text" (mais avec un maxlength à 12, pas opportun pour les gabarits).

Cette partie n'était plus effective avec l'ajout des opérateurs, le render_widget() appelle directement render_content(), qui ne passait pas par le gabarit HTML du widget, et fournissait déjà un input type="text" (mais avec un maxlength à 12, pas opportun pour les gabarits).
# field filter dialog content
r += htmltext('<div style="display: none;">')
r += htmltext('<ul id="field-filter" class="objects-list">')
@ -2215,7 +2209,7 @@ class FormPage(Directory, TempfileDirectoryMixin):
filter_field_value = False
else:
raise RequestError('Invalid value "%s" for "%s"' % (filter_field_value, filter_field_key))
elif filter_field.key in ('item', 'items', 'string', 'email', 'numeric'):
elif filter_field.key in ('item', 'items', 'string', 'email', 'numeric', 'date'):
if Template.is_template_string(filter_field_value, ezt_support=False):
if keep_templates:
# use Equal criteria here, the only use is in CardDef.get_data_source_referenced_varnames