add activity field to report, is also used as query field with vocabulary
This commit is contained in:
parent
354dfeda7f
commit
17f15429c8
6 changed files with 92 additions and 30 deletions
|
@ -262,6 +262,12 @@ table.records th, table.records td {
|
||||||
border: 1px solid lightgrey;
|
border: 1px solid lightgrey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table.report {
|
||||||
|
position: relative;
|
||||||
|
z-index: 99;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
table.report th {
|
table.report th {
|
||||||
border-bottom: 1px solid #bbbbbb;
|
border-bottom: 1px solid #bbbbbb;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|
|
@ -141,7 +141,14 @@
|
||||||
|
|
||||||
|
|
||||||
<metal:field define-macro="selection">
|
<metal:field define-macro="selection">
|
||||||
<metal:use use-macro="item/report_macros/textline" />
|
<select tal:attributes="name name">
|
||||||
|
<option />
|
||||||
|
<option tal:repeat="opt python:field.getVocabularyItems(
|
||||||
|
context=item.adapted, request=request)"
|
||||||
|
tal:attributes="value opt/token;
|
||||||
|
selected python:value == opt['token']"
|
||||||
|
tal:content="opt/title" />
|
||||||
|
</select>
|
||||||
</metal:field>
|
</metal:field>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,7 @@ class IntegerField(Field):
|
||||||
|
|
||||||
class DateField(Field):
|
class DateField(Field):
|
||||||
|
|
||||||
fieldType='date',
|
fieldType='date'
|
||||||
format = ('date', 'short')
|
format = ('date', 'short')
|
||||||
renderer = cssClass = 'center'
|
renderer = cssClass = 'center'
|
||||||
dbtype = 'date'
|
dbtype = 'date'
|
||||||
|
@ -192,6 +192,8 @@ class WorkItemStateField(Field):
|
||||||
class VocabularyField(Field):
|
class VocabularyField(Field):
|
||||||
|
|
||||||
vocabulary = None
|
vocabulary = None
|
||||||
|
sourceList = None
|
||||||
|
fieldType = 'selection'
|
||||||
|
|
||||||
def getDisplayValue(self, row):
|
def getDisplayValue(self, row):
|
||||||
value = self.getRawValue(row)
|
value = self.getRawValue(row)
|
||||||
|
@ -202,9 +204,11 @@ class VocabularyField(Field):
|
||||||
if str(item['token']) == str(value):
|
if str(item['token']) == str(value):
|
||||||
return item['title']
|
return item['title']
|
||||||
|
|
||||||
def getVocabularyItems(self, row):
|
def getVocabularyItems(self, row=None, context=None, request=None):
|
||||||
context = row.context
|
if context is None:
|
||||||
request = row.parent.context.view.request
|
context = row.context
|
||||||
|
if request is None:
|
||||||
|
request = row.parent.context.view.request
|
||||||
voc = self.vocabulary
|
voc = self.vocabulary
|
||||||
if isinstance(voc, basestring):
|
if isinstance(voc, basestring):
|
||||||
terms = self.getVocabularyTerms(voc, context, request)
|
terms = self.getVocabularyTerms(voc, context, request)
|
||||||
|
@ -213,7 +217,10 @@ class VocabularyField(Field):
|
||||||
voc = voc.splitlines()
|
voc = voc.splitlines()
|
||||||
return [dict(token=t, title=t) for t in voc if t.strip()]
|
return [dict(token=t, title=t) for t in voc if t.strip()]
|
||||||
elif IContextSourceBinder.providedBy(voc):
|
elif IContextSourceBinder.providedBy(voc):
|
||||||
source = voc(row.parent.context)
|
if row is not None:
|
||||||
|
source = voc(row.parent.context)
|
||||||
|
else:
|
||||||
|
source = voc(context)
|
||||||
terms = component.queryMultiAdapter((source, request), ITerms)
|
terms = component.queryMultiAdapter((source, request), ITerms)
|
||||||
if terms is not None:
|
if terms is not None:
|
||||||
termsList = [terms.getTerm(value) for value in source]
|
termsList = [terms.getTerm(value) for value in source]
|
||||||
|
|
|
@ -232,7 +232,7 @@ The user interface is a ReportConceptView subclass that is directly associated w
|
||||||
... print
|
... print
|
||||||
08/12/28 19:00 20:15
|
08/12/28 19:00 20:15
|
||||||
{'url': '.../home/.36', 'title': u'loops Development'}
|
{'url': '.../home/.36', 'title': u'loops Development'}
|
||||||
{'url': '.../home/.33', 'title': u'john'} 01:15 00:15
|
{'url': '.../home/.33', 'title': u'john'} 00:15
|
||||||
{'actions': [...]}
|
{'actions': [...]}
|
||||||
|
|
||||||
>>> results.totals.data
|
>>> results.totals.data
|
||||||
|
@ -247,8 +247,8 @@ Export of work data
|
||||||
|
|
||||||
>>> output = reportView()
|
>>> output = reportView()
|
||||||
>>> print output
|
>>> print output
|
||||||
Day;Start;End;Task;Party;Title;Duration;Effort;State
|
Day;Start;End;Task;Party;Title;LA;Effort;State
|
||||||
08/12/28;19:00;20:15;loops Development;john;;1.2500;0.2500;finished
|
08/12/28;19:00;20:15;loops Development;john;;;0.2500;finished
|
||||||
|
|
||||||
|
|
||||||
Meeting Minutes
|
Meeting Minutes
|
||||||
|
|
|
@ -39,11 +39,13 @@ from loops.common import adapted, baseObject
|
||||||
from loops.expert.browser.export import ResultsConceptCSVExport
|
from loops.expert.browser.export import ResultsConceptCSVExport
|
||||||
from loops.expert.browser.report import ReportConceptView
|
from loops.expert.browser.report import ReportConceptView
|
||||||
from loops.expert.field import Field, TargetField, DateField, StateField, \
|
from loops.expert.field import Field, TargetField, DateField, StateField, \
|
||||||
StringField, TextField, HtmlTextField, UrlField
|
StringField, TextField, HtmlTextField, \
|
||||||
|
UrlField, VocabularyField
|
||||||
from loops.expert.field import SubReport, SubReportField
|
from loops.expert.field import SubReport, SubReportField
|
||||||
from loops.expert.field import TrackDateField, TrackTimeField, TrackDateTimeField
|
from loops.expert.field import TrackDateField, TrackTimeField, TrackDateTimeField
|
||||||
from loops.expert.field import WorkItemStateField
|
from loops.expert.field import WorkItemStateField
|
||||||
from loops.expert.report import ReportInstance
|
from loops.expert.report import ReportInstance
|
||||||
|
from loops.table import DataTableSourceBinder, DataTableSourceListByValue
|
||||||
from loops import util
|
from loops import util
|
||||||
|
|
||||||
|
|
||||||
|
@ -114,6 +116,28 @@ class PartyStateField(StateField):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class ActivityField(VocabularyField):
|
||||||
|
|
||||||
|
tableName = 'organize.work.activities'
|
||||||
|
vocabulary = DataTableSourceBinder(tableName,
|
||||||
|
sourceList=DataTableSourceListByValue)
|
||||||
|
|
||||||
|
def getDisplayValue(self, row):
|
||||||
|
if row.context is None:
|
||||||
|
return u'-'
|
||||||
|
value = row.context.data.get('activity', '')#[:3]
|
||||||
|
if not value:
|
||||||
|
return u''
|
||||||
|
dt = row.parent.context.view.conceptManager.get(self.tableName)
|
||||||
|
if dt is None:
|
||||||
|
return u''
|
||||||
|
for row in adapted(dt).data.values():
|
||||||
|
if row[0] == value:
|
||||||
|
value = row[3]
|
||||||
|
break
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
def daysAgoByOption(context):
|
def daysAgoByOption(context):
|
||||||
days = 7
|
days = 7
|
||||||
opt = context.view.typeOptions('workitem_dayfrom_default')
|
opt = context.view.typeOptions('workitem_dayfrom_default')
|
||||||
|
@ -193,7 +217,10 @@ partyState = PartyStateField('partyState', u'Party State',
|
||||||
cssClass='center',
|
cssClass='center',
|
||||||
statesDefinition='contact_states',
|
statesDefinition='contact_states',
|
||||||
executionSteps=['query', 'output'])
|
executionSteps=['query', 'output'])
|
||||||
# activity
|
activity = ActivityField('activity', u'LA',
|
||||||
|
description=u'The activity assigned to the work item.',
|
||||||
|
fieldType='selection',
|
||||||
|
executionSteps=['query', 'sort', 'output'])
|
||||||
# process
|
# process
|
||||||
|
|
||||||
|
|
||||||
|
@ -233,7 +260,7 @@ class WorkRow(BaseRow):
|
||||||
attributeHandlers = dict(day=getDay,
|
attributeHandlers = dict(day=getDay,
|
||||||
dayStart=getStart, dayEnd=getEnd,
|
dayStart=getStart, dayEnd=getEnd,
|
||||||
dayFrom=getDay, dayTo=getDay,
|
dayFrom=getDay, dayTo=getDay,
|
||||||
duration=getDuration, effort=getEffort,)
|
duration=getDuration, effort=getEffort)
|
||||||
|
|
||||||
|
|
||||||
class WorkReportInstance(ReportInstance):
|
class WorkReportInstance(ReportInstance):
|
||||||
|
@ -246,9 +273,11 @@ class WorkReportInstance(ReportInstance):
|
||||||
fields = Jeep((dayFrom, dayTo, tasks,
|
fields = Jeep((dayFrom, dayTo, tasks,
|
||||||
day, timeStart, timeEnd, task, party, workTitle,
|
day, timeStart, timeEnd, task, party, workTitle,
|
||||||
#description,
|
#description,
|
||||||
duration, effort, state))
|
activity,
|
||||||
|
#duration,
|
||||||
|
effort, state))
|
||||||
|
|
||||||
userSettings = (dayFrom, dayTo, party)
|
userSettings = (dayFrom, dayTo, party, activity)
|
||||||
defaultOutputFields = fields
|
defaultOutputFields = fields
|
||||||
defaultSortCriteria = (day, timeStart,)
|
defaultSortCriteria = (day, timeStart,)
|
||||||
defaultStates = ('done', 'done_x', 'finished')
|
defaultStates = ('done', 'done_x', 'finished')
|
||||||
|
|
45
table.py
45
table.py
|
@ -138,22 +138,6 @@ def getRowValue(k, v):
|
||||||
def getRowValueWithKey(k, v):
|
def getRowValueWithKey(k, v):
|
||||||
return u' '.join((unicode(k), v[0]))
|
return u' '.join((unicode(k), v[0]))
|
||||||
|
|
||||||
class DataTableSourceBinder(object):
|
|
||||||
|
|
||||||
implements(IContextSourceBinder)
|
|
||||||
|
|
||||||
def __init__(self, tableName, valueProvider=getRowValue):
|
|
||||||
self.tableName = tableName
|
|
||||||
self.valueProvider = valueProvider
|
|
||||||
|
|
||||||
def __call__(self, instance):
|
|
||||||
if IInstance.providedBy(instance):
|
|
||||||
context = instance.view.nodeView.context
|
|
||||||
else:
|
|
||||||
context = baseObject(instance.context)
|
|
||||||
dt = context.getLoopsRoot().getConceptManager()[self.tableName]
|
|
||||||
return DataTableSourceList(adapted(dt), self.valueProvider)
|
|
||||||
|
|
||||||
|
|
||||||
class DataTableSourceList(object):
|
class DataTableSourceList(object):
|
||||||
|
|
||||||
|
@ -170,3 +154,32 @@ class DataTableSourceList(object):
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self.context.data)
|
return len(self.context.data)
|
||||||
|
|
||||||
|
|
||||||
|
class DataTableSourceListByValue(DataTableSourceList):
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
items = [(k, v[0], v[1])
|
||||||
|
for k, v in self.context.data.items()]
|
||||||
|
items.sort()
|
||||||
|
return iter([(i[1], i[2]) for i in items])
|
||||||
|
|
||||||
|
|
||||||
|
class DataTableSourceBinder(object):
|
||||||
|
|
||||||
|
implements(IContextSourceBinder)
|
||||||
|
|
||||||
|
def __init__(self, tableName, valueProvider=getRowValue,
|
||||||
|
sourceList=None):
|
||||||
|
self.tableName = tableName
|
||||||
|
self.valueProvider = valueProvider
|
||||||
|
self.sourceList = sourceList or DataTableSourceList
|
||||||
|
|
||||||
|
def __call__(self, instance):
|
||||||
|
if IInstance.providedBy(instance):
|
||||||
|
context = instance.view.nodeView.context
|
||||||
|
else:
|
||||||
|
context = baseObject(instance.context)
|
||||||
|
dt = context.getLoopsRoot().getConceptManager()[self.tableName]
|
||||||
|
return self.sourceList(adapted(dt), self.valueProvider)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue