backoffice: custom view datasource, return all options (#77302) #320
|
@ -1207,7 +1207,7 @@ def test_backoffice_custom_view_boolean_filters(pub):
|
|||
assert resp.text.count('data-link=') == 5
|
||||
|
||||
|
||||
def test_item_options_in_dynamic_view(pub):
|
||||
def test_item_options_in_custom_view(pub):
|
||||
pub.user_class.wipe()
|
||||
create_superuser(pub)
|
||||
pub.role_class.wipe()
|
||||
|
@ -1223,12 +1223,39 @@ def test_item_options_in_dynamic_view(pub):
|
|||
fields.StringField(
|
||||
id='1',
|
||||
label='1st field',
|
||||
type='string',
|
||||
),
|
||||
fields.ItemField(
|
||||
id='2',
|
||||
label='2nd field',
|
||||
type='item',
|
||||
items=list('azertyuiopqsdfghjklmwxcvbn')[:16],
|
||||
display_locations=['validation', 'summary', 'listings'],
|
||||
display_mode='list',
|
||||
),
|
||||
fields.ItemField(
|
||||
id='3',
|
||||
label='3rd field',
|
||||
type='item',
|
||||
items=list('azertyuiopqsdfghjklmwxcvbn')[:15],
|
||||
display_locations=['validation', 'summary', 'listings'],
|
||||
display_mode='list',
|
||||
),
|
||||
fields.ItemField(
|
||||
id='4',
|
||||
label='4th field',
|
||||
items=['â', 'b', 'c', 'd'],
|
||||
type='item',
|
||||
items=list('azertyuiopqsdfghjklmwxcvbn')[:16],
|
||||
display_locations=['validation', 'summary', 'listings'],
|
||||
display_mode='autocomplete',
|
||||
),
|
||||
fields.ItemField(
|
||||
id='5',
|
||||
label='5th field',
|
||||
type='item',
|
||||
items=list('azertyuiopqsdfghjklmwxcvbn')[:15],
|
||||
display_locations=['validation', 'summary', 'listings'],
|
||||
display_mode='autocomplete',
|
||||
),
|
||||
]
|
||||
carddef.workflow_roles = {'_editor': role.id}
|
||||
|
@ -1241,55 +1268,102 @@ def test_item_options_in_dynamic_view(pub):
|
|||
carddata = data_class()
|
||||
carddata.data = {
|
||||
'1': 'plop%s' % (i % 2),
|
||||
'2': 'a%s' % (i % 4),
|
||||
'2_display': 'a%s' % (i % 4),
|
||||
'3': 'a%s' % (i % 4),
|
||||
'3_display': 'a%s' % (i % 4),
|
||||
'4': 'a%s' % (i % 4),
|
||||
'4_display': 'a%s' % (i % 4),
|
||||
'5': 'a%s' % (i % 4),
|
||||
'5_display': 'a%s' % (i % 4),
|
||||
}
|
||||
carddata.just_created()
|
||||
carddata.store()
|
||||
|
||||
custom_view = pub.custom_view_class()
|
||||
custom_view.title = 'custom test view'
|
||||
custom_view.formdef = carddef
|
||||
custom_view.visibility = 'datasource'
|
||||
custom_view.columns = {'list': [{'id': '1'}]}
|
||||
custom_view.filters = {}
|
||||
custom_view.store()
|
||||
datasource_custom_view = pub.custom_view_class()
|
||||
datasource_custom_view.title = 'custom test view for datasource'
|
||||
datasource_custom_view.formdef = carddef
|
||||
datasource_custom_view.visibility = 'datasource'
|
||||
datasource_custom_view.columns = {'list': [{'id': '1'}]}
|
||||
datasource_custom_view.filters = {}
|
||||
datasource_custom_view.store()
|
||||
|
||||
any_custom_view = pub.custom_view_class()
|
||||
any_custom_view.title = 'custom test view for anyone'
|
||||
any_custom_view.formdef = carddef
|
||||
any_custom_view.visibility = 'any'
|
||||
any_custom_view.columns = {'list': [{'id': '1'}]}
|
||||
any_custom_view.filters = {}
|
||||
any_custom_view.store()
|
||||
|
||||
app = login(get_app(pub))
|
||||
resp = app.get('/backoffice/data/card-title/custom-test-view/')
|
||||
|
||||
# enable both filters
|
||||
resp = app.get('/backoffice/data/card-title/custom-test-view-for-anyone/')
|
||||
# enable filters
|
||||
resp.forms['listing-settings']['filter-1'].checked = True
|
||||
resp.forms['listing-settings']['filter-2'].checked = True
|
||||
resp.forms['listing-settings']['filter-3'].checked = True
|
||||
resp.forms['listing-settings']['filter-4'].checked = True
|
||||
resp.forms['listing-settings']['filter-5'].checked = True
|
||||
resp = resp.forms['listing-settings'].submit()
|
||||
# all used options are listed ({} is "custom value")
|
||||
assert [x[0] for x in resp.forms['listing-settings']['filter-4-value'].options] == [
|
||||
|
||||
# field 2: select - all used options are listed
|
||||
assert [x[0] for x in resp.forms['listing-settings']['filter-2-value'].options] == [
|
||||
'',
|
||||
'a0',
|
||||
'a1',
|
||||
'a2',
|
||||
'a3',
|
||||
'{}',
|
||||
]
|
||||
|
||||
# plain filter, only used options are listed
|
||||
resp.forms['listing-settings']['filter-1-value'].value = 'plop0'
|
||||
resp.forms['listing-settings']['filter-4-value'].value = 'a0'
|
||||
resp = resp.forms['listing-settings'].submit()
|
||||
assert [x[0] for x in resp.forms['listing-settings']['filter-4-value'].options] == ['', 'a0', 'a2', '{}']
|
||||
|
||||
# template filter, all options are listed
|
||||
resp.forms['listing-settings']['filter-1-value'].value = '{{ test }}'
|
||||
resp = resp.forms['listing-settings'].submit()
|
||||
assert [x[0] for x in resp.forms['listing-settings']['filter-4-value'].options] == [
|
||||
# field 3: select - all used options are listed
|
||||
assert [x[0] for x in resp.forms['listing-settings']['filter-3-value'].options] == [
|
||||
'',
|
||||
'a0',
|
||||
'a1',
|
||||
'a2',
|
||||
'a3',
|
||||
'{}',
|
||||
]
|
||||
|
||||
# field 4: select2 - all used options are listed
|
||||
assert [x[0] for x in resp.forms['listing-settings']['filter-4-value'].options] == ['']
|
||||
resp2 = app.get(resp.request.path + 'filter-options?filter_field_id=4&_search=')
|
||||
assert [x['id'] for x in resp2.json['data']] == ['a0', 'a1', 'a2', 'a3']
|
||||
|
||||
# field 5: select2 - all used options are listed
|
||||
assert [x[0] for x in resp.forms['listing-settings']['filter-5-value'].options] == ['']
|
||||
resp2 = app.get(resp.request.path + 'filter-options?filter_field_id=5&_search=')
|
||||
assert [x['id'] for x in resp2.json['data']] == ['a0', 'a1', 'a2', 'a3']
|
||||
|
||||
resp = app.get('/backoffice/data/card-title/custom-test-view-for-datasource/')
|
||||
# enable filters
|
||||
resp.forms['listing-settings']['filter-1'].checked = True
|
||||
resp.forms['listing-settings']['filter-2'].checked = True
|
||||
resp.forms['listing-settings']['filter-3'].checked = True
|
||||
resp.forms['listing-settings']['filter-4'].checked = True
|
||||
resp.forms['listing-settings']['filter-5'].checked = True
|
||||
resp = resp.forms['listing-settings'].submit()
|
||||
|
||||
# field 2: select2 - all items are listed
|
||||
assert [x[0] for x in resp.forms['listing-settings']['filter-2-value'].options] == ['', '{}']
|
||||
resp2 = app.get(resp.request.path + 'filter-options?filter_field_id=2&_search=')
|
||||
assert [x['id'] for x in resp2.json['data']] == list('azertyuiopqsdfghjklmwxcvbn')[:15] + ['{}']
|
||||
|
||||
# field 3: select - all items are listed
|
||||
assert [x[0] for x in resp.forms['listing-settings']['filter-3-value'].options] == [''] + list(
|
||||
'azertyuiopqsdfghjklmwxcvbn'
|
||||
)[:15] + ['{}']
|
||||
|
||||
# field 4: select2 - all items are listed
|
||||
assert [x[0] for x in resp.forms['listing-settings']['filter-4-value'].options] == ['', '{}']
|
||||
resp2 = app.get(resp.request.path + 'filter-options?filter_field_id=4&_search=')
|
||||
assert [x['id'] for x in resp2.json['data']] == list('azertyuiopqsdfghjklmwxcvbn')[:15] + ['{}']
|
||||
|
||||
# field 5: select - all items are listed
|
||||
assert [x[0] for x in resp.forms['listing-settings']['filter-5-value'].options] == [''] + list(
|
||||
'azertyuiopqsdfghjklmwxcvbn'
|
||||
)[:15] + ['{}']
|
||||
|
||||
|
||||
@pytest.mark.parametrize('user_perms', ['admin', 'category_admin', 'category_not_admin', 'agent'])
|
||||
def test_backoffice_hidden_data_source_custom_view(pub, user_perms):
|
||||
|
|
|
@ -382,6 +382,31 @@ def test_backoffice_item_filter(pub):
|
|||
else:
|
||||
assert [x['id'] for x in resp2.json['data']] == ['â', 'b', 'd']
|
||||
|
||||
# item field in autocomplete mode, check that label is weel displayed in option
|
||||
CardDef.wipe()
|
||||
carddef = CardDef()
|
||||
carddef.name = 'foo'
|
||||
carddef.fields = [
|
||||
fields.StringField(id='1', label='Test', type='string', varname='foo'),
|
||||
]
|
||||
carddef.digest_templates = {'default': 'card {{ form_var_foo }}'}
|
||||
carddef.store()
|
||||
|
||||
card_ids = {}
|
||||
for label in ('foo', 'bar', 'baz', 'foo, bar'):
|
||||
card = carddef.data_class()()
|
||||
card.data = {'1': label}
|
||||
card.just_created()
|
||||
card.store()
|
||||
card_ids[label] = str(card.id)
|
||||
formdef.fields[0].display_mode = 'autocomplete'
|
||||
formdef.fields[0].data_source = {'type': 'carddef:foo', 'value': ''}
|
||||
formdef.store()
|
||||
|
||||
resp.forms['listing-settings']['filter-4-value'].force_value(card_ids['baz'])
|
||||
resp = resp.forms['listing-settings'].submit()
|
||||
assert [x[2] for x in resp.forms['listing-settings']['filter-4-value'].options] == ['card baz']
|
||||
|
||||
|
||||
def test_backoffice_item_double_filter(pub):
|
||||
pub.user_class.wipe()
|
||||
|
|
|
@ -937,6 +937,8 @@ class FormPage(FormdefDirectoryBase):
|
|||
criterias=None,
|
||||
anonymised=False,
|
||||
):
|
||||
if self.view and self.view.visibility == 'datasource':
|
||||
return filter_field.get_options()
|
||||
# remove potential filter on self
|
||||
filter_field_id = get_field_id(filter_field)
|
||||
filtered_criterias = []
|
||||
|
@ -981,22 +983,9 @@ class FormPage(FormdefDirectoryBase):
|
|||
# for item/items fields, get actual option values from database
|
||||
if not getattr(filter_field, 'block_field', None):
|
||||
criterias.append(NotNull(sql.get_field_id(filter_field)))
|
||||
if self.view and self.view.visibility == 'datasource':
|
||||
# for custom views used as data sources ignore criterias
|
||||
# that would result in an empty list of options.
|
||||
# (either "Nothing" or a template string)
|
||||
options_criterias = []
|
||||
for criteria in criterias:
|
||||
if isinstance(criteria, Nothing):
|
||||
continue
|
||||
if Template.is_template_string(getattr(criteria, 'value', '')):
|
||||
continue
|
||||
options_criterias.append(criteria)
|
||||
else:
|
||||
options_criterias = criterias
|
||||
options = self.formdef.data_class().select_distinct(
|
||||
[sql.get_field_id(filter_field), '%s_display' % sql.get_field_id(filter_field)],
|
||||
clause=options_criterias,
|
||||
clause=criterias,
|
||||
)
|
||||
else:
|
||||
# in case of blocks, this requires digging into the jsonb columns,
|
||||
|
@ -1046,7 +1035,7 @@ class FormPage(FormdefDirectoryBase):
|
|||
term = get_request().form.get('_search')
|
||||
if term:
|
||||
options = [x for x in options if term.lower() in x[1].lower()]
|
||||
options = options[:15]
|
||||
options = options[:15]
|
||||
if self.view and self.view.visibility == 'datasource':
|
||||
options.append(('{}', _('custom value')))
|
||||
get_response().set_content_type('application/json')
|
||||
|
@ -1298,36 +1287,50 @@ class FormPage(FormdefDirectoryBase):
|
|||
elif filter_field.key in ('item', 'items'):
|
||||
filter_field.required = False
|
||||
|
||||
# Get options from existing formdatas.
|
||||
# Get options from existing formdatas, except for custom views with visibility "datasource"
|
||||
# This allows for options that don't appear anymore in the
|
||||
# data source to be listed (for example because the field
|
||||
# is using a parametrized URL depending on unavailable
|
||||
# variables, or simply returning different results now).
|
||||
is_datasource_customview = self.view and self.view.visibility == 'datasource'
|
||||
|
||||
display_mode = 'select'
|
||||
if filter_field.key == 'item' and filter_field.get_display_mode() == 'autocomplete':
|
||||
if (
|
||||
not is_datasource_customview
|
||||
and filter_field.key == 'item'
|
||||
and filter_field.get_display_mode() == 'autocomplete'
|
||||
):
|
||||
display_mode = 'select2'
|
||||
if is_datasource_customview:
|
||||
options = filter_field.get_options()
|
||||
if len(options) > 15:
|
||||
display_mode = 'select2'
|
||||
|
||||
is_multi_values = filter_field_operator in ['in', 'not_in', 'between']
|
||||
if display_mode == 'select':
|
||||
options = self.get_item_filter_options(
|
||||
filter_field,
|
||||
selected_filter,
|
||||
selected_filter_operator,
|
||||
criterias,
|
||||
)
|
||||
options = [(x[0], x[1], x[0]) for x in options]
|
||||
if not is_datasource_customview:
|
||||
options = self.get_item_filter_options(
|
||||
filter_field,
|
||||
selected_filter,
|
||||
selected_filter_operator,
|
||||
criterias,
|
||||
)
|
||||
options = [(x[0], x[1], x[0]) for x in options]
|
||||
options.insert(0, (None, '', ''))
|
||||
attrs = {'data-refresh-options': str(filter_field.contextual_id)}
|
||||
else:
|
||||
options = [(None, '', '')]
|
||||
if not is_multi_values:
|
||||
options = [(filter_field_value, filter_field_value or '', filter_field_value or '')]
|
||||
value_display = filter_field_value or ''
|
||||
if filter_field_value:
|
||||
value_display = filter_field.get_display_value(filter_field_value)
|
||||
options = [(filter_field_value, value_display, filter_field_value or '')]
|
||||
attrs = {'data-remote-options': str(filter_field.contextual_id)}
|
||||
get_response().add_javascript(
|
||||
['jquery.js', '../../i18n.js', 'qommon.forms.js', 'select2.js']
|
||||
)
|
||||
get_response().add_css_include('select2.css')
|
||||
if self.view and self.view.visibility == 'datasource':
|
||||
if is_datasource_customview:
|
||||
options.append(('{}', _('custom value'), '{}'))
|
||||
if filter_field_value and filter_field_value not in [x[0] for x in options]:
|
||||
options.append((filter_field_value, filter_field_value, filter_field_value))
|
||||
|
|
Loading…
Reference in New Issue