backoffice: link to related card (#73690) #87

Merged
lguerin merged 1 commits from wip/73690-card-link into main 2023-05-02 14:17:32 +02:00
13 changed files with 98 additions and 29 deletions

View File

@ -1330,10 +1330,16 @@ def test_carddata_add_edit_related(pub):
assert '/backoffice/data/child/add/?_popup=1' in resp
assert resp.pyquery('select#form_f1').attr('data-initial-edit-related-url') == ''
assert resp.pyquery('#edit_form_f1.edit-related')
assert resp.pyquery('select#form_f1').attr('data-initial-view-related-url') == ''
assert resp.pyquery('#view_form_f1.view-related')
assert resp.pyquery('select#form_f2').attr('data-initial-edit-related-url') == ''
assert resp.pyquery('#edit_form_f2.edit-related')
assert resp.pyquery('select#form_f2').attr('data-initial-view-related-url') == ''
assert resp.pyquery('#view_form_f2.view-related')
assert resp.pyquery('select#form_f3__element0__f1').attr('data-initial-edit-related-url') == ''
assert resp.pyquery('#edit_form_f3__element0__f1.edit-related')
assert resp.pyquery('select#form_f3__element0__f1').attr('data-initial-view-related-url') == ''
assert resp.pyquery('#view_form_f3__element0__f1.view-related')
resp_popup = app.get('/backoffice/data/adult/add/?_popup=1')
assert 'select2.min.js' in resp_popup.text
@ -1348,10 +1354,16 @@ def test_carddata_add_edit_related(pub):
assert '/backoffice/data/child/add/?_popup=1' in resp
assert resp.pyquery('select#form_f1').attr('data-initial-edit-related-url') is None
assert not resp.pyquery('#edit_form_f1.edit-related')
assert resp.pyquery('select#form_f1').attr('data-initial-view-related-url') is None
assert not resp.pyquery('#view_form_f1.view-related')
assert resp.pyquery('select#form_f2').attr('data-initial-edit-related-url') == ''
assert resp.pyquery('#edit_form_f2.edit-related')
assert resp.pyquery('select#form_f2').attr('data-initial-view-related-url') == ''
assert resp.pyquery('#view_form_f2.view-related')
assert resp.pyquery('select#form_f3__element0__f1').attr('data-initial-edit-related-url') == ''
assert resp.pyquery('#edit_form_f3__element0__f1.edit-related')
assert resp.pyquery('select#form_f3__element0__f1').attr('data-initial-view-related-url') == ''
assert resp.pyquery('#view_form_f3__element0__f1.view-related')
# check creation and edition in popup
resp = app.get('/backoffice/data/child/add/?_popup=1')
@ -1411,16 +1423,28 @@ def test_carddata_add_edit_related(pub):
assert '/backoffice/data/child/add/?_popup=1' in resp
assert resp.pyquery('select#form_f1').attr('data-initial-edit-related-url') is None
assert not resp.pyquery('#edit_form_f1.edit-related')
assert resp.pyquery('select#form_f1').attr('data-initial-view-related-url') is None
assert not resp.pyquery('#view_form_f1.view-related')
assert (
resp.pyquery('select#form_f2').attr('data-initial-edit-related-url')
== 'http://example.net/backoffice/data/adult/%s/wfedit-_editable' % adultdata2.id
)
assert resp.pyquery('#edit_form_f2.edit-related')
assert (
resp.pyquery('select#form_f2').attr('data-initial-view-related-url')
== 'http://example.net/backoffice/data/adult/%s/' % adultdata2.id
)
assert resp.pyquery('#view_form_f2.view-related')
assert (
resp.pyquery('select#form_f3__element0__f1').attr('data-initial-edit-related-url')
== 'http://example.net/backoffice/data/child/%s/wfedit-_editable' % childdata.id
)
assert resp.pyquery('#edit_form_f3__element0__f1.edit-related')
assert (
resp.pyquery('select#form_f3__element0__f1').attr('data-initial-view-related-url')
== 'http://example.net/backoffice/data/child/%s/' % childdata.id
)
assert resp.pyquery('#view_form_f3__element0__f1.view-related')
# check autocomplete result
# no query, no edit url
@ -1443,11 +1467,13 @@ def test_carddata_add_edit_related(pub):
'id': 1,
'text': 'foo bar 1',
'edit_related_url': 'http://example.net/backoffice/data/adult/1/wfedit-_editable',
'view_related_url': 'http://example.net/backoffice/data/adult/1/',
},
{
'id': 2,
'text': 'foo bar 2',
'edit_related_url': 'http://example.net/backoffice/data/adult/2/wfedit-_editable',
'view_related_url': 'http://example.net/backoffice/data/adult/2/',
},
]
}
@ -1459,19 +1485,21 @@ def test_carddata_add_edit_related(pub):
assert 'Add another Child' not in resp
assert '/backoffice/data/child/add/?_popup=1' not in resp
# user has no edit rights on adult
# user has no edit and no view rights on adult
adult.workflow_roles = {}
adult.store()
resp = app.get('/backoffice/data/family/%s/wfedit-_editable' % familydata.id)
assert resp.pyquery('select#form_f2').attr('data-initial-edit-related-url') == ''
assert resp.pyquery('#edit_form_f2.edit-related')
assert resp.pyquery('select#form_f2').attr('data-initial-view-related-url') == ''
assert resp.pyquery('#view_form_f2.view-related')
autocomplete_resp = app.get(
resp.pyquery('select#form_f2').attr('data-select2-url') + '?q=foo&page_limit=10'
)
assert autocomplete_resp.json == {
'data': [
{'id': 1, 'text': 'foo bar 1', 'edit_related_url': ''},
{'id': 2, 'text': 'foo bar 2', 'edit_related_url': ''},
{'id': 1, 'text': 'foo bar 1', 'edit_related_url': '', 'view_related_url': ''},
{'id': 2, 'text': 'foo bar 2', 'edit_related_url': '', 'view_related_url': ''},
]
}

View File

@ -1211,18 +1211,18 @@ class AutocompleteDirectory(Directory):
custom_view.filters = info['dynamic_custom_view_filters']
query = get_request().form.get('q', '')
limit = get_request().form.get('page_limit')
edit_related = info.get('edit_related')
with_edit_related_url = query and limit and edit_related
with_related = info.get('with_related')
with_related_urls = query and limit and with_related
values = CardDef.get_data_source_items(
carddef_ref,
custom_view=custom_view,
query=query,
limit=limit,
with_edit_related_url=with_edit_related_url,
with_related_urls=with_related_urls,
)
keys = ['id', 'text']
if with_edit_related_url:
keys.append('edit_related_url')
if with_related_urls:
keys += ['edit_related_url', 'view_related_url']
return json.dumps({'data': [{key: x.get(key, '') for key in keys} for x in values]})

View File

@ -371,6 +371,7 @@ class CardFillPage(FormFillPage):
'value': str(filled.id),
'obj': str(filled.default_digest),
'edit_related_url': filled.get_edit_related_url() or '',
'view_related_url': filled.get_view_related_url() or '',
}
)
return template.QommonTemplateResponse(

View File

@ -36,7 +36,7 @@ class CardData(FormData):
formdef = property(get_formdef)
def get_data_source_structured_item(self, digest_key='default', with_edit_related_url=False):
def get_data_source_structured_item(self, digest_key='default', with_related_urls=False):
if self.digests is None:
if digest_key == 'default':
summary = _('Digest (default) not defined')
@ -48,10 +48,13 @@ class CardData(FormData):
'id': self.id,
'text': (self.digests or {}).get(digest_key) or '',
}
if with_edit_related_url:
if with_related_urls:
edit_related_url = self.get_edit_related_url()
if edit_related_url:
item['edit_related_url'] = edit_related_url
view_related_url = self.get_view_related_url()
if view_related_url:
item['view_related_url'] = view_related_url
for field in self.formdef.get_all_fields():
if not field.varname or field.varname in ('id', 'text'):
continue
@ -76,6 +79,11 @@ class CardData(FormData):
+ 'wfedit-%s' % _item.id
)
def get_view_related_url(self):
if not self.formdef.is_user_allowed_read(get_request().user, self):
return
return self.get_url(backoffice=True)
def get_display_label(self, digest_key='default'):
return (self.digests or {}).get(digest_key) or self.get_display_name()

View File

@ -190,7 +190,7 @@ class CardDef(FormDef):
custom_view=None,
get_by_id=None,
get_by_text=None,
with_edit_related_url=False,
with_related_urls=False,
):
assert data_source_id.startswith('carddef:')
parts = data_source_id.split(':')
@ -251,9 +251,7 @@ class CardDef(FormDef):
criterias.append(ElementEqual('digests', digest_key, get_by_text))
items = [
x.get_data_source_structured_item(
digest_key=digest_key, with_edit_related_url=with_edit_related_url
)
x.get_data_source_structured_item(digest_key=digest_key, with_related_urls=with_related_urls)
for x in carddef.data_class().select(clause=criterias, order_by=order_by, limit=limit)
]
if order_by is None:

View File

@ -2249,7 +2249,7 @@ class ItemFieldMixin:
carddef = self.get_carddef()
url_kwargs = {}
if self.key == 'item' and get_request().is_in_backoffice() and carddef:
url_kwargs['edit_related'] = True
url_kwargs['with_related'] = True
# store display value in session to be used by select2
url = data_source.get_jsonp_url(**url_kwargs)
if not session.jsonp_display_values:
@ -2355,8 +2355,8 @@ class ItemField(WidgetField, MapOptionsMixin, ItemFieldMixin):
if get_request().is_in_backoffice() and carddef:
if carddef.can_user_add_cards(get_request().user):
kwargs['add_related_url'] = carddef.get_backoffice_submission_url()
kwargs['edit_related'] = True
url_kwargs['edit_related'] = True
kwargs['with_related'] = True
url_kwargs['with_related'] = True
self.url = kwargs['url'] = data_source.get_jsonp_url(**url_kwargs)
self.widget_class = JsonpSingleSelectWidget
return

View File

@ -1844,6 +1844,7 @@ class FormPage(FormdefDirectoryBase, FormTemplateMixin):
'value': str(self.edited_data.id),
'obj': str(self.edited_data.default_digest),
'edit_related_url': self.edited_data.get_edit_related_url() or '',
'view_related_url': self.edited_data.get_view_related_url() or '',
}
)
return template.QommonTemplateResponse(

View File

@ -2967,11 +2967,11 @@ class RankedItemsWidget(CompositeWidget):
class JsonpSingleSelectWidget(Widget):
template_name = 'qommon/forms/widgets/select_jsonp.html'
def __init__(self, name, value=None, url=None, add_related_url=None, edit_related=False, **kwargs):
def __init__(self, name, value=None, url=None, add_related_url=None, with_related=False, **kwargs):
super().__init__(name, value=value, **kwargs)
self.url = url
self.add_related_url = add_related_url
self.edit_related = edit_related
self.with_related = with_related
def add_media(self):
get_response().add_javascript(['select2.js'])
@ -2995,9 +2995,7 @@ class JsonpSingleSelectWidget(Widget):
return get_session().jsonp_display_values.get(key)
def get_edit_related_url(self):
if not self.edit_related:
return
def _get_carddata(self):
if self.value is None:
value = None
else:
@ -3011,11 +3009,26 @@ class JsonpSingleSelectWidget(Widget):
if not carddef:
return
try:
carddata = carddef.data_class().get(value)
return carddef.data_class().get(value)
except KeyError:
return
def get_edit_related_url(self):
if not self.with_related:
return
carddata = self._get_carddata()
if not carddata:
return
return carddata.get_edit_related_url()
def get_view_related_url(self):
if not self.with_related:
return
carddata = self._get_carddata()
if not carddata:
return
return carddata.get_view_related_url()
def get_select2_url(self):
if Template.is_template_string(self.url):
vars = get_publisher().substitutions.get_context_variables(mode='lazy')

View File

@ -2359,7 +2359,7 @@ div.timetable-widget {
.wcs-widget-select2-container {
display: flex;
.add-related, .edit-related {
.add-related, .edit-related, .view-related {
margin-top: 2px; // == margin-top of span.select2-container
margin-left: 3px;
}
@ -2374,6 +2374,10 @@ div.timetable-widget {
background-image: url(/static/css/icons/action-edit.hover.png);
}
}
.view-related {
line-height: 2em;
border: none;
}
}
.wcs-block-with-remove-button {

View File

@ -1,4 +1,4 @@
(function() {
var initData = JSON.parse(document.getElementById('popup-response-constants').dataset.popupResponse);
opener.dismissRelatedObjectPopup(window, initData.value, initData.obj, initData.edit_related_url);
opener.dismissRelatedObjectPopup(window, initData.value, initData.obj, initData.edit_related_url, initData.view_related_url);
})();

View File

@ -399,7 +399,7 @@ $(function() {
return showPopup(triggeringLink, /^(edit|add)_/);
}
function dismissRelatedObjectPopup(win, newId, newRepr, edit_related_url) {
function dismissRelatedObjectPopup(win, newId, newRepr, edit_related_url, view_related_url) {
var name = windowname_to_id(win.name);
var elem = document.getElementById(name);
if (elem) {
@ -409,6 +409,9 @@ $(function() {
if (edit_related_url) {
$option.attr('data-edit-related-url', edit_related_url);
}
if (view_related_url) {
$option.attr('data-view-related-url', view_related_url);
}
$(elem).append($option);
}
// Trigger a change event to update related links if required.

View File

@ -348,6 +348,9 @@ $(function() {
if (data.edit_related_url) {
$(data.element).attr('data-edit-related-url', data.edit_related_url);
}
if (data.view_related_url) {
$(data.element).attr('data-view-related-url', data.view_related_url);
}
return data.text;
}
};
@ -389,11 +392,15 @@ $(function() {
var $selected = $(elem).find(':selected').first();
var text = $selected.text();
$input_display_value.val(text);
// update edit-related button href
// update edit-related button and view-related link href
$(elem).siblings('.edit-related').attr('href', '').hide();
$(elem).siblings('.view-related').attr('href', '').hide();
if ($selected.attr('data-edit-related-url')) {
$(elem).siblings('.edit-related').attr('href', $selected.attr('data-edit-related-url') + '?_popup=1').show();
}
if ($selected.attr('data-view-related-url')) {
$(elem).siblings('.view-related').attr('href', $selected.attr('data-view-related-url')).show();
}
});
if ($input_display_value.val()) {
// if the _display hidden field was created with an initial value take it
@ -405,6 +412,9 @@ $(function() {
if ($(elem).data('initial-edit-related-url')) {
option.attr('data-edit-related-url', $(elem).data('initial-edit-related-url'));
}
if ($(elem).data('initial-view-related-url')) {
option.attr('data-view-related-url', $(elem).data('initial-view-related-url'));
}
select2.val($(elem).data('value')).trigger('change');
$(elem).select2('data', {id: $(elem).data('value'), text: $(elem).data('initial-display-value')});
}

View File

@ -7,18 +7,21 @@
{% if widget.value %}data-value="{{ widget.value }}"{% endif %}
data-required="{% if widget.is_required %}true{% endif %}"
data-initial-display-value="{{widget.get_display_value|default_if_none:''}}"
{% if widget.edit_related %}data-initial-edit-related-url="{{widget.get_edit_related_url|default_if_none:''}}"{% endif %}>
{% if widget.with_related %}data-initial-edit-related-url="{{widget.get_edit_related_url|default_if_none:''}}"{% endif %}
{% if widget.with_related %}data-initial-view-related-url="{{widget.get_view_related_url|default_if_none:''}}"{% endif %}>
</select>
{% if widget.add_related_url %}
<a class="add-related pk-button" id="add_form_{{ widget.get_name_for_id }}"
href="{{ widget.add_related_url }}?_popup=1"
title="{% blocktrans with card=widget.get_title %}Add another {{ card }}{% endblocktrans %}">+</a>
{% endif %}
{% if widget.edit_related %}
{% if widget.with_related %}
<a class="edit-related pk-button" id="edit_form_{{ widget.get_name_for_id }}"
style="display: none"
title="{% blocktrans with card=widget.get_title %}Edit selected {{ card }}{% endblocktrans %}"
>{% blocktrans with card=widget.get_title %}Edit selected {{ card }}{% endblocktrans %}</a>
<a class="view-related" id="view_form_{{ widget.get_name_for_id }}"
style="display: none">{% blocktrans with card=widget.get_title %}See selected {{ card }}{% endblocktrans %}</a>
{% endif %}
</div>
{% endblock %}