diff --git a/CHANGES.rst b/CHANGES.rst
index b5d3da8f88..6d63973231 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -13,6 +13,7 @@ Changelog
**Changed**
+- #1427 Improved performance of Sample header table rendering
- #1417 Cache allowed transitions for analyses on the request
- #1413 Improved Email Publication
diff --git a/bika/lims/browser/analysisrequest/__init__.py b/bika/lims/browser/analysisrequest/__init__.py
index f7d6d981ec..2a4f544279 100644
--- a/bika/lims/browser/analysisrequest/__init__.py
+++ b/bika/lims/browser/analysisrequest/__init__.py
@@ -109,7 +109,12 @@ def __call__(self, request, data):
if not self.include_fields or "Analyses" in self.include_fields:
data['Analyses'] = self.ar_analysis_values()
-class mailto_link_from_contacts:
+
+class mailto_link_from_contacts(object):
+ """Custom header table field adapter
+
+ see: bika.lims.browser.header_table
+ """
def __init__(self, context):
self.context = context
@@ -127,7 +132,12 @@ def __call__(self, field):
return ",".join(ret)
-def mailto_link_from_ccemails(ccemails):
+class mailto_link_from_ccemails(object):
+ """Custom header table field adapter
+
+ see: bika.lims.browser.header_table
+ """
+
def __init__(self, context):
self.context = context
@@ -136,6 +146,7 @@ def __call__(self, field):
addresses = ccemails.split(",")
ret = []
for address in addresses:
+ address = address.strip()
mailto = "%s" % (
address, address)
ret.append(mailto)
diff --git a/bika/lims/browser/analysisrequest/configure.zcml b/bika/lims/browser/analysisrequest/configure.zcml
index 3f8d33e7a1..a695e2556a 100644
--- a/bika/lims/browser/analysisrequest/configure.zcml
+++ b/bika/lims/browser/analysisrequest/configure.zcml
@@ -57,6 +57,7 @@
provides="bika.lims.interfaces.IJSONReadExtender"
/>
+
-1
+
+ @cache(field_type_cache_key, get_cache=store_on_portal)
+ def is_boolean_field(self, field):
+ """Check if the field is a boolean
+ """
+ return field.getWidgetName() == "BooleanWidget"
+
+ @cache(field_type_cache_key, get_cache=store_on_portal)
+ def is_date_field(self, field):
+ """Check if the field is a date field
+ """
+ return field.getType().lower().find("datetime") > -1
+
+ def get_boolean_field_data(self, field):
+ """Get boolean field view data for the template
+ """
+ value = field.get(self.context)
+ fieldname = field.getName()
+
+ return {
+ "fieldName": fieldname,
+ "mode": "structure",
+ "html": t(_("Yes")) if value else t(_("No"))
+ }
+
+ def get_reference_field_data(self, field):
+ """Get reference field view data for the template
+ """
+ targets = None
+ fieldname = field.getName()
+
+ accessor = getattr(self.context, "get%s" % fieldname, None)
+ if accessor and callable(accessor):
+ targets = accessor()
+ else:
+ targets = field.get(self.context)
+
+ if targets:
+ if not isinstance(targets, list):
+ targets = [targets, ]
+
+ if all([check_permission(view, target) for target in targets]):
+ elements = [
+ ""
+ .format(id=target.getId(),
+ uid=target.UID(),
+ url=target.absolute_url(),
+ title=target.Title())
+ for target in targets]
+
+ return {
+ "fieldName": fieldname,
+ "mode": "structure",
+ "html": "".join(elements),
+ }
+ else:
+ return {
+ "fieldName": fieldname,
+ "mode": "structure",
+ "html": ", ".join([ta.Title() for ta in targets]),
+ }
+
+ return {
+ "fieldName": fieldname,
+ "mode": "structure",
+ "html": ""
+ }
+
+ def get_date_field_data(self, field):
+ """Render date field view data for the template
+ """
+ value = field.get(self.context)
+ fieldname = field.getName()
+
+ return {
+ "fieldName": fieldname,
+ "mode": "structure",
+ "html": self.ulocalized_time(value, long_format=True)
+ }
+
def three_column_list(self, input_list):
list_len = len(input_list)
@@ -84,82 +195,37 @@ def _list_end(num):
final.append(column)
return final
- # TODO Revisit this
def render_field_view(self, field):
fieldname = field.getName()
- field = self.context.Schema()[fieldname]
- ret = {"fieldName": fieldname, "mode": "view"}
- try:
- adapter = getAdapter(self.context,
- interface=IHeaderTableFieldRenderer,
- name=fieldname)
-
- except ComponentLookupError:
- adapter = None
- if adapter:
- ret = {'fieldName': fieldname,
- 'mode': 'structure',
- 'html': adapter(field)}
- else:
- if field.getWidgetName() == "BooleanWidget":
- value = field.get(self.context)
- ret = {
- "fieldName": fieldname,
- "mode": "structure",
- "html": t(_("Yes")) if value else t(_("No"))
- }
- elif field.getType().find("Reference") > -1:
- # Prioritize method retrieval over schema"s field
- targets = None
- if hasattr(self.context, "get%s" % fieldname):
- fieldaccessor = getattr(self.context, "get%s" % fieldname)
- if callable(fieldaccessor):
- targets = fieldaccessor()
- if not targets:
- targets = field.get(self.context)
-
- if targets:
- if not type(targets) == list:
- targets = [targets, ]
- sm = getSecurityManager()
- if all([sm.checkPermission(view, ta) for ta in targets]):
- elements = [
- ""
- .format(id=target.getId(),
- uid=target.UID(),
- url=target.absolute_url(),
- title=target.Title())
- for target in targets]
-
- ret = {
- "fieldName": fieldname,
- "mode": "structure",
- "html": "".join(elements),
- }
- else:
- ret = {
- "fieldName": fieldname,
- "mode": "structure",
- "html": ", ".join([ta.Title() for ta in targets]),
- }
- else:
- ret = {
- "fieldName": fieldname,
- "mode": "structure",
- "html": "",
- }
- elif field.getType().lower().find("datetime") > -1:
- value = field.get(self.context)
- ret = {
- "fieldName": fieldname,
+
+ # lookup custom render adapter
+ adapter = queryAdapter(self.context,
+ interface=IHeaderTableFieldRenderer,
+ name=fieldname)
+
+ # Note: Adapters for contact fields:
+ # bika.lims.browser.analysisrequest.mailto_link_from_contacts
+ # bika.lims.browser.analysisrequest.mailto_link_from_ccemails
+ #
+ # -> TODO Remove?
+
+ # return immediately if we have an adapter
+ if adapter is not None:
+ return {"fieldName": fieldname,
"mode": "structure",
- "html": self.ulocalized_time(value, long_format=True)
- }
- return ret
+ "html": adapter(field)}
+
+ # field data for *view* mode for the template
+ data = {"fieldName": fieldname, "mode": "view"}
+
+ if self.is_boolean_field(field):
+ data = self.get_boolean_field_data(field)
+ elif self.is_reference_field(field):
+ data = self.get_reference_field_data(field)
+ elif self.is_date_field(field):
+ data = self.get_date_field_data(field)
+
+ return data
def get_field_visibility_mode(self, field):
"""Returns "view" or "edit" modes, together with the place within where
@@ -179,8 +245,7 @@ def get_field_visibility_mode(self, field):
# modes) only if the current user has enough privileges.
if field.checkPermission("edit", self.context):
mode = "edit"
- sm = getSecurityManager()
- if not sm.checkPermission(ModifyPortalContent, self.context):
+ if not self.is_edit_allowed():
logger.warn("Permission '{}' granted for the edition of '{}', "
"but 'Modify portal content' not granted"
.format(field.write_permission, field.getName()))
diff --git a/bika/lims/browser/templates/header_table.pt b/bika/lims/browser/templates/header_table.pt
index 34ca0b119a..22f48884db 100644
--- a/bika/lims/browser/templates/header_table.pt
+++ b/bika/lims/browser/templates/header_table.pt
@@ -12,12 +12,9 @@