Wrong index type for selection strings that are not multivalued.
This commit is contained in:
parent
7c2b8fed11
commit
9f4db88bdf
|
@ -402,11 +402,12 @@ class Type:
|
||||||
res = True
|
res = True
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def isSortable(self, usage='search'):
|
def isSortable(self, usage):
|
||||||
'''Can fields of this type be used for sorting purposes (when sorting
|
'''Can fields of this type be used for sorting purposes (when sorting
|
||||||
search results (p_usage="search") or when sorting reference fields
|
search results (p_usage="search") or when sorting reference fields
|
||||||
(p_usage="ref")?'''
|
(p_usage="ref")?'''
|
||||||
if usage == 'search': return self.indexed
|
if usage == 'search':
|
||||||
|
return self.indexed and not self.isMultiValued()
|
||||||
elif usage == 'ref':
|
elif usage == 'ref':
|
||||||
return self.type in ('Integer', 'Float', 'Boolean', 'Date') or \
|
return self.type in ('Integer', 'Float', 'Boolean', 'Date') or \
|
||||||
((self.type == 'String') and (self.format == 0))
|
((self.type == 'String') and (self.format == 0))
|
||||||
|
|
|
@ -120,7 +120,7 @@ class Table(LayoutElement):
|
||||||
'''Represents a table where to dispose graphical elements.'''
|
'''Represents a table where to dispose graphical elements.'''
|
||||||
simpleParams = ('style', 'css_class', 'cellpadding', 'cellspacing', 'width',
|
simpleParams = ('style', 'css_class', 'cellpadding', 'cellspacing', 'width',
|
||||||
'align')
|
'align')
|
||||||
derivedRepls = {'view': 'hrv', 'cell': 'l'}
|
derivedRepls = {'view': 'hrv', 'cell': 'ld'}
|
||||||
def __init__(self, layoutString=None, style=None, css_class='',
|
def __init__(self, layoutString=None, style=None, css_class='',
|
||||||
cellpadding=0, cellspacing=0, width='100%', align='left',
|
cellpadding=0, cellspacing=0, width='100%', align='left',
|
||||||
other=None, derivedType=None):
|
other=None, derivedType=None):
|
||||||
|
@ -191,7 +191,9 @@ class Table(LayoutElement):
|
||||||
if char in rowDelimiters:
|
if char in rowDelimiters:
|
||||||
valign = rowDelimiters[char]
|
valign = rowDelimiters[char]
|
||||||
if self.isHeaderRow(rowContent):
|
if self.isHeaderRow(rowContent):
|
||||||
self.headerRow = Row(rowContent,valign,isHeader=True).get()
|
if not self.headerRow:
|
||||||
|
self.headerRow = Row(rowContent, valign,
|
||||||
|
isHeader=True).get()
|
||||||
else:
|
else:
|
||||||
self.rows.append(Row(rowContent, valign).get())
|
self.rows.append(Row(rowContent, valign).get())
|
||||||
rowContent = ''
|
rowContent = ''
|
||||||
|
|
|
@ -451,7 +451,8 @@ class PloneInstaller:
|
||||||
n = appyType.name
|
n = appyType.name
|
||||||
indexName = 'get%s%s' % (n[0].upper(), n[1:])
|
indexName = 'get%s%s' % (n[0].upper(), n[1:])
|
||||||
indexType = 'FieldIndex'
|
indexType = 'FieldIndex'
|
||||||
if (appyType.type == 'String') and appyType.isSelect:
|
if (appyType.type == 'String') and appyType.isSelect and \
|
||||||
|
appyType.isMultiValued():
|
||||||
indexType = 'ZCTextIndex'
|
indexType = 'ZCTextIndex'
|
||||||
indexInfo[indexName] = indexType
|
indexInfo[indexName] = indexType
|
||||||
if indexInfo:
|
if indexInfo:
|
||||||
|
|
|
@ -275,6 +275,14 @@ class ToolMixin(AbstractMixin):
|
||||||
return value[:maxWidth] + '...'
|
return value[:maxWidth] + '...'
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
def truncateText(self, text, width=15):
|
||||||
|
'''Truncates p_text to max p_width chars. If the text is longer than
|
||||||
|
p_width, the truncated part is put in a "acronym" html tag.'''
|
||||||
|
if len(text) <= width: return text
|
||||||
|
else:
|
||||||
|
return '<acronym title="%s">%s</acronym>' % \
|
||||||
|
(text, text[:width] + '...')
|
||||||
|
|
||||||
translationMapping = {'portal_path': ''}
|
translationMapping = {'portal_path': ''}
|
||||||
def translateWithMapping(self, label):
|
def translateWithMapping(self, label):
|
||||||
'''Translates p_label in the application domain, with a default
|
'''Translates p_label in the application domain, with a default
|
||||||
|
@ -336,15 +344,13 @@ class ToolMixin(AbstractMixin):
|
||||||
res[means.id] = means.__dict__
|
res[means.id] = means.__dict__
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def userMayAdd(self, rootClass):
|
def userMaySearch(self, rootClass):
|
||||||
'''For deciding if a user may add a new instance of a class, beyond the
|
'''This method checks if the currently logged user can trigger searches
|
||||||
permission-based check, we can have a custom method that proposes an
|
on a given p_rootClass. This is done by calling method "maySearch"
|
||||||
additional condition. This method checks if there is such a custom
|
on the class. If no such method exists, we return True.'''
|
||||||
method (must be named "mayCreate") define on p_rootClass, and calls
|
|
||||||
it if yes. If no, it returns True.'''
|
|
||||||
pythonClass = self.getAppyClass(rootClass)
|
pythonClass = self.getAppyClass(rootClass)
|
||||||
if 'mayCreate' in pythonClass.__dict__:
|
if 'maySearch' in pythonClass.__dict__:
|
||||||
return pythonClass.mayCreate(self.appy())
|
return pythonClass.maySearch(self.appy())
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def onImportObjects(self):
|
def onImportObjects(self):
|
||||||
|
@ -369,6 +375,12 @@ class ToolMixin(AbstractMixin):
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def isSortable(self, name, className, usage):
|
||||||
|
'''Is field p_name defined on p_metaType sortable for p_usage purposes
|
||||||
|
(p_usage can be "ref" or "search")?'''
|
||||||
|
appyType = self.getAppyType(name, className=className)
|
||||||
|
return appyType.isSortable(usage=usage)
|
||||||
|
|
||||||
def _searchValueIsEmpty(self, key):
|
def _searchValueIsEmpty(self, key):
|
||||||
'''Returns True if request value in key p_key can be considered as
|
'''Returns True if request value in key p_key can be considered as
|
||||||
empty.'''
|
empty.'''
|
||||||
|
|
|
@ -642,11 +642,6 @@ class AbstractMixin:
|
||||||
reverse = rq.get('reverse') == 'True'
|
reverse = rq.get('reverse') == 'True'
|
||||||
self.appy().sort(fieldName, sortKey=sortKey, reverse=reverse)
|
self.appy().sort(fieldName, sortKey=sortKey, reverse=reverse)
|
||||||
|
|
||||||
def isRefSortable(self, fieldName):
|
|
||||||
'''Can p_fieldName, which is a field defined on self, be used as a sort
|
|
||||||
key in a reference field?'''
|
|
||||||
return self.getAppyType(fieldName).isSortable(usage='ref')
|
|
||||||
|
|
||||||
def getWorkflow(self, appy=True):
|
def getWorkflow(self, appy=True):
|
||||||
'''Returns the Appy workflow instance that is relevant for this
|
'''Returns the Appy workflow instance that is relevant for this
|
||||||
object. If p_appy is False, it returns the DC workflow.'''
|
object. If p_appy is False, it returns the DC workflow.'''
|
||||||
|
@ -969,6 +964,7 @@ class AbstractMixin:
|
||||||
if created and rq.get('nav', None):
|
if created and rq.get('nav', None):
|
||||||
# Get the initiator
|
# Get the initiator
|
||||||
splitted = rq['nav'].split('.')
|
splitted = rq['nav'].split('.')
|
||||||
|
if splitted[0] == 'search': return # Not an initiator but a search.
|
||||||
initiator = self.uid_catalog.searchResults(
|
initiator = self.uid_catalog.searchResults(
|
||||||
UID=splitted[1])[0].getObject()
|
UID=splitted[1])[0].getObject()
|
||||||
fieldName = splitted[2].split(':')[1]
|
fieldName = splitted[2].split(':')[1]
|
||||||
|
|
|
@ -54,18 +54,18 @@
|
||||||
<tal:comment replace="nothing">Mandatory column "Title"/"Name"</tal:comment>
|
<tal:comment replace="nothing">Mandatory column "Title"/"Name"</tal:comment>
|
||||||
|
|
||||||
<th tal:define="fieldName python:'title'; sortable python:True; filterable python:True">
|
<th tal:define="fieldName python:'title'; sortable python:True; filterable python:True">
|
||||||
<span tal:content="python: tool.translate('ref_name')"/>
|
<span tal:replace="structure python: tool.truncateText(tool.translate('ref_name'))"/>
|
||||||
<metal:sortAndFilter use-macro="here/skyn/navigate/macros/sortAndFilter"/>
|
<metal:sortAndFilter use-macro="here/skyn/navigate/macros/sortAndFilter"/>
|
||||||
</th>
|
</th>
|
||||||
|
|
||||||
<tal:comment replace="nothing">Columns corresponding to other fields</tal:comment>
|
<tal:comment replace="nothing">Columns corresponding to other fields</tal:comment>
|
||||||
<tal:columnHeader repeat="fieldDescr fieldDescrs">
|
<tal:columnHeader repeat="fieldDescr fieldDescrs">
|
||||||
<th tal:define="fieldName fieldDescr/name|string:workflow_state;
|
<th tal:define="fieldName fieldDescr/name|string:workflow_state;
|
||||||
sortable fieldDescr/indexed|nothing;
|
sortable python: tool.isSortable(fieldName, contentType, 'search');
|
||||||
filterable fieldDescr/filterable|nothing;">
|
filterable fieldDescr/filterable|nothing;">
|
||||||
<tal:comment replace="nothing">Display header for a "standard" field</tal:comment>
|
<tal:comment replace="nothing">Display header for a "standard" field</tal:comment>
|
||||||
<tal:standardField condition="python: fieldName != 'workflow_state'">
|
<tal:standardField condition="python: fieldName != 'workflow_state'">
|
||||||
<span tal:replace="python: tool.translate(fieldDescr['labelId'])"/>
|
<span tal:replace="structure python: tool.truncateText(tool.translate(fieldDescr['labelId']))"/>
|
||||||
</tal:standardField>
|
</tal:standardField>
|
||||||
<tal:comment replace="nothing">Display header for the workflow state</tal:comment>
|
<tal:comment replace="nothing">Display header for the workflow state</tal:comment>
|
||||||
<tal:workflowState condition="python: fieldName == 'workflow_state'">
|
<tal:workflowState condition="python: fieldName == 'workflow_state'">
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
title allows to see all root objects in the database.</tal:comment>
|
title allows to see all root objects in the database.</tal:comment>
|
||||||
<table cellpadding="0" cellspacing="0" width="100%">
|
<table cellpadding="0" cellspacing="0" width="100%">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td tal:define="titleIsClickable python: member.has_role('Manager') and rootClasses">
|
||||||
<a tal:condition="python: len(flavours)==1 and rootClasses"
|
<a tal:condition="titleIsClickable"
|
||||||
tal:attributes="href python:'%s?type_name=%s&flavourNumber=1' % (queryUrl, ','.join(rootClasses))"
|
tal:attributes="href python:'%s?type_name=%s&flavourNumber=1' % (queryUrl, ','.join(rootClasses))"
|
||||||
tal:content="python: tool.translate(appName)"></a>
|
tal:content="python: tool.translate(appName)"></a>
|
||||||
<span tal:condition="python: len(flavours)>1 or not rootClasses"
|
<span tal:condition="not: titleIsClickable"
|
||||||
tal:replace="python: tool.translate(appName)"/>
|
tal:replace="python: tool.translate(appName)"/>
|
||||||
</td>
|
</td>
|
||||||
<td align="right">
|
<td align="right">
|
||||||
|
@ -36,14 +36,13 @@
|
||||||
<dt class="portletAppyItem"><metal:phases use-macro="here/skyn/portlet/macros/phases"/></dt>
|
<dt class="portletAppyItem"><metal:phases use-macro="here/skyn/portlet/macros/phases"/></dt>
|
||||||
</tal:publishedObject>
|
</tal:publishedObject>
|
||||||
|
|
||||||
<tal:comment replace="nothing">TODO: implement a widget for selecting the needed flavour.</tal:comment>
|
|
||||||
|
|
||||||
<tal:comment replace="nothing">Create a section for every root class.</tal:comment>
|
<tal:comment replace="nothing">Create a section for every root class.</tal:comment>
|
||||||
<tal:section repeat="rootClass rootClasses"
|
<tal:section repeat="rootClass rootClasses"
|
||||||
define="flavourNumber python:1;
|
define="flavourNumber python:1;
|
||||||
flavour python: tool.getFlavour('Dummy_%d' % flavourNumber)">
|
flavour python: tool.getFlavour('Dummy_%d' % flavourNumber)">
|
||||||
<tal:comment replace="nothing">Section title, with action icons</tal:comment>
|
<tal:comment replace="nothing">Section title, with action icons</tal:comment>
|
||||||
<dt tal:attributes="class python:test((repeat['rootClass'].number()==1) and not contextObj, 'portletAppyItem', 'portletAppyItem portletSep')">
|
<dt tal:condition="python: tool.userMaySearch(rootClass)"
|
||||||
|
tal:attributes="class python:test((repeat['rootClass'].number()==1) and not contextObj, 'portletAppyItem', 'portletAppyItem portletSep')">
|
||||||
<table width="100%" cellspacing="0" cellpadding="0" class="no-style-table">
|
<table width="100%" cellspacing="0" cellpadding="0" class="no-style-table">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
|
@ -53,7 +52,7 @@
|
||||||
</td>
|
</td>
|
||||||
<td align="right"
|
<td align="right"
|
||||||
tal:define="addPermission python: '%s: Add %s' % (appName, rootClass);
|
tal:define="addPermission python: '%s: Add %s' % (appName, rootClass);
|
||||||
userMayAdd python: member.has_permission(addPermission, appFolder) and tool.userMayAdd(rootClass);
|
userMayAdd python: member.has_permission(addPermission, appFolder);
|
||||||
createMeans python: tool.getCreateMeans(rootClass)">
|
createMeans python: tool.getCreateMeans(rootClass)">
|
||||||
<tal:comment replace="nothing">Create a new object from a web form</tal:comment>
|
<tal:comment replace="nothing">Create a new object from a web form</tal:comment>
|
||||||
<img style="cursor:pointer"
|
<img style="cursor:pointer"
|
||||||
|
|
|
@ -74,7 +74,7 @@
|
||||||
ref field according to the field that corresponds to this column.
|
ref field according to the field that corresponds to this column.
|
||||||
</tal:comment>
|
</tal:comment>
|
||||||
<metal:sortIcons define-macro="sortIcons"
|
<metal:sortIcons define-macro="sortIcons"
|
||||||
tal:define="ajaxBaseCall python: navBaseCall.replace('**v**', '\'%s\',\'SortReference\', {\'sortKey\':\'%s\', \'reverse\':\'**v**\'}' % (startNumber, shownField))" tal:condition="python: canWrite and objs[0].isRefSortable(shownField)">
|
tal:define="ajaxBaseCall python: navBaseCall.replace('**v**', '\'%s\',\'SortReference\', {\'sortKey\':\'%s\', \'reverse\':\'**v**\'}' % (startNumber, shownField))" tal:condition="python: canWrite and tool.isSortable(shownField, objs[0].meta_type, 'ref')">
|
||||||
<img style="cursor:pointer"
|
<img style="cursor:pointer"
|
||||||
tal:attributes="src string:$portal_url/skyn/sortAsc.png;
|
tal:attributes="src string:$portal_url/skyn/sortAsc.png;
|
||||||
onClick python: ajaxBaseCall.replace('**v**', 'False')"/>
|
onClick python: ajaxBaseCall.replace('**v**', 'False')"/>
|
||||||
|
|
|
@ -46,7 +46,7 @@ class FlavourWrapper(AbstractWrapper):
|
||||||
p_attrName.
|
p_attrName.
|
||||||
|
|
||||||
"resultColumns"
|
"resultColumns"
|
||||||
Stores the list of columns that must be show when displaying
|
Stores the list of columns that must be shown when displaying
|
||||||
instances of the a given root p_klass.
|
instances of the a given root p_klass.
|
||||||
|
|
||||||
"enableAdvancedSearch"
|
"enableAdvancedSearch"
|
||||||
|
|
Loading…
Reference in a new issue