misc: add autocomplete support to live dynamic custom views (#48472)
This commit is contained in:
parent
71a4174d63
commit
00f1b271b4
|
@ -6091,7 +6091,7 @@ def test_dynamic_item_field_from_custom_view_on_cards(pub):
|
|||
formdef.store()
|
||||
|
||||
resp = get_app(pub).get('/test/')
|
||||
assert len(resp.form['f1'].options) == 1
|
||||
assert resp.form['f1'].options == [('', False, '---')]
|
||||
resp.form['f0'] = 'baz'
|
||||
live_resp = app.post('/test/live?modified_field_id=0', params=resp.form.submit_fields())
|
||||
assert len(live_resp.json['result']['1']['items']) == 10
|
||||
|
@ -6102,7 +6102,33 @@ def test_dynamic_item_field_from_custom_view_on_cards(pub):
|
|||
# simulate javascript filling the <select>
|
||||
resp.form['f1'].options.append((item['id'], False, item['text']))
|
||||
|
||||
resp.form['f1'] = resp.form['f1'].options[0][0]
|
||||
resp.form['f1'] = resp.form['f1'].options[0][0]
|
||||
resp = resp.form.submit('submit') # -> validation page
|
||||
resp = resp.form.submit('submit') # -> submit
|
||||
assert formdef.data_class().select()[0].data['1'] in baz_ids
|
||||
assert formdef.data_class().select()[0].data['1_structured']['item'] == 'baz'
|
||||
|
||||
# same in autocomplete mode
|
||||
formdef.fields[1].display_mode = 'autocomplete'
|
||||
formdef.store()
|
||||
app = get_app(pub)
|
||||
resp = app.get('/test/')
|
||||
# simulate select2 mode, with qommon.forms.js adding an extra hidden widget
|
||||
resp.form.fields['f1_display'] = Hidden(form=resp.form, tag='input', name='f1_display', pos=10)
|
||||
select2_url = resp.pyquery('select:last').attr['data-select2-url']
|
||||
resp_json = app.get(select2_url + '?q=')
|
||||
assert len(resp_json.json['data']) == 0
|
||||
resp.form['f0'] = 'baz'
|
||||
|
||||
live_resp = app.post('/test/live?modified_field_id=0', params=resp.form.submit_fields())
|
||||
new_select2_url = live_resp.json['result']['1']['source_url']
|
||||
resp_json = app.get(new_select2_url + '?q=')
|
||||
assert len(resp_json.json['data']) == 10
|
||||
assert set([str(x['id']) for x in resp_json.json['data']]) == baz_ids
|
||||
|
||||
resp.form['f1'].force_value(str(resp_json.json['data'][0]['id']))
|
||||
resp.form.fields['f1_display'].force_value(resp_json.json['data'][0]['text'])
|
||||
|
||||
resp = resp.form.submit('submit') # -> validation page
|
||||
resp = resp.form.submit('submit') # -> submit
|
||||
assert formdef.data_class().select()[0].data['1'] in baz_ids
|
||||
|
|
35
wcs/api.py
35
wcs/api.py
|
@ -877,17 +877,30 @@ class AutocompleteDirectory(Directory):
|
|||
if not info:
|
||||
raise AccessForbiddenError()
|
||||
get_response().set_content_type('application/json')
|
||||
if info.startswith('carddef:'):
|
||||
from wcs.carddef import CardDef
|
||||
values = CardDef.get_data_source_items(info,
|
||||
query=get_request().form['q'],
|
||||
limit=get_request().form.get('page_limit'))
|
||||
return json.dumps({'data': [{'id': x['id'], 'text': x['text']} for x in values]})
|
||||
url = info
|
||||
url += urllib.quote(get_request().form['q'])
|
||||
url = sign_url_auto_orig(url)
|
||||
get_response().set_content_type('application/json')
|
||||
return misc.urlopen(url).read()
|
||||
|
||||
if isinstance(info, str) and not info.startswith('carddef:'):
|
||||
# legacy json source
|
||||
info = {'url': info}
|
||||
elif isinstance(info, str):
|
||||
# legacy carddef source
|
||||
info = {'carddef_ref': info}
|
||||
|
||||
if 'url' in info:
|
||||
url = info['url']
|
||||
url += urllib.quote(get_request().form['q'])
|
||||
url = sign_url_auto_orig(url)
|
||||
get_response().set_content_type('application/json')
|
||||
return misc.urlopen(url).read()
|
||||
|
||||
# carddef_ref in info
|
||||
carddef_ref = info['carddef_ref']
|
||||
from wcs.carddef import CardDef
|
||||
values = CardDef.get_data_source_items(
|
||||
carddef_ref,
|
||||
custom_view=info.get('dynamic_custom_view'),
|
||||
query=get_request().form['q'],
|
||||
limit=get_request().form.get('page_limit'))
|
||||
return json.dumps({'data': [{'id': x['id'], 'text': x['text']} for x in values]})
|
||||
|
||||
|
||||
class ApiDirectory(Directory):
|
||||
|
|
|
@ -193,7 +193,7 @@ class CardDef(FormDef):
|
|||
|
||||
@classmethod
|
||||
def get_data_source_items(cls, data_source_id, query=None, limit=None,
|
||||
get_by_id=None, get_by_text=None):
|
||||
custom_view=None, get_by_id=None, get_by_text=None):
|
||||
from wcs.workflows import WorkflowStatusItem
|
||||
assert data_source_id.startswith('carddef:')
|
||||
parts = data_source_id.split(':')
|
||||
|
@ -204,9 +204,10 @@ class CardDef(FormDef):
|
|||
criterias = [NotEqual('status', 'draft')]
|
||||
order_by = None
|
||||
if len(parts) > 2:
|
||||
custom_view = cls.get_data_source_custom_view(data_source_id)
|
||||
if not custom_view:
|
||||
return []
|
||||
if custom_view is None:
|
||||
custom_view = cls.get_data_source_custom_view(data_source_id)
|
||||
if not custom_view:
|
||||
return []
|
||||
order_by = custom_view.order_by
|
||||
criterias.extend(cls.get_data_source_criterias(carddef, custom_view))
|
||||
for criteria in criterias:
|
||||
|
|
|
@ -468,11 +468,35 @@ class NamedDataSource(XmlStorableObject):
|
|||
if self.type == 'jsonp':
|
||||
return self.data_source.get('value')
|
||||
if self.type == 'json' and self.query_parameter:
|
||||
json_url = self.get_json_query_url()
|
||||
info = None
|
||||
if json_url:
|
||||
info = {'url': json_url}
|
||||
return '/api/autocomplete/%s' % (
|
||||
get_session().get_data_source_query_info_token(self.get_json_query_url()))
|
||||
get_session().get_data_source_query_info_token(info))
|
||||
if self.type and self.type.startswith('carddef:'):
|
||||
parts = self.type.split(':')
|
||||
if len(parts) > 2:
|
||||
# custom view, check if it's dynamic
|
||||
from wcs.carddef import CardDef
|
||||
from wcs.workflows import WorkflowStatusItem
|
||||
custom_view = CardDef.get_data_source_custom_view(self.type)
|
||||
had_template = False
|
||||
for filter_key, filter_value in custom_view.filters.items():
|
||||
if not Template.is_template_string(filter_value):
|
||||
continue
|
||||
custom_view.filters[filter_key] = WorkflowStatusItem.compute(filter_value)
|
||||
had_template = True
|
||||
if had_template:
|
||||
# keep altered custom view in session
|
||||
return '/api/autocomplete/%s' % (
|
||||
get_session().get_data_source_query_info_token({
|
||||
'carddef_ref': self.type,
|
||||
'dynamic_custom_view': custom_view}))
|
||||
return '/api/autocomplete/%s' % (
|
||||
get_session().get_data_source_query_info_token(self.type))
|
||||
get_session().get_data_source_query_info_token({
|
||||
'carddef_ref': self.type,
|
||||
}))
|
||||
return None
|
||||
|
||||
def get_value_by_id(self, param_name, param_value):
|
||||
|
|
|
@ -701,11 +701,11 @@ class FormStatusPage(Directory, FormTemplateMixin):
|
|||
continue
|
||||
varnames = data_source.get_referenced_varnames(field.formdef)
|
||||
if (not modified_field_varnames or modified_field_varnames.intersection(varnames)) and (
|
||||
field.display_mode == 'autocomplete' and data_source.query_parameter):
|
||||
field.display_mode == 'autocomplete' and data_source.can_jsonp()):
|
||||
# computed earlier, in perform_more_widget_changes, when the field
|
||||
# was added to the form
|
||||
result[field.id]['source_url'] = field.url
|
||||
if modified_field_varnames.intersection(varnames):
|
||||
elif modified_field_varnames.intersection(varnames):
|
||||
if 'template-' in (field.extra_css_class or ''):
|
||||
# custom template, it may need all option attributes
|
||||
result[field.id]['items'] = field.get_extended_options()
|
||||
|
|
Loading…
Reference in New Issue