add activity field to report, is also used as query field with vocabulary

This commit is contained in:
Helmut Merz 2016-03-18 15:57:26 +01:00
parent 354dfeda7f
commit 17f15429c8
6 changed files with 92 additions and 30 deletions

View file

@ -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;

View file

@ -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>

View file

@ -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,8 +204,10 @@ 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):
if context is None:
context = row.context context = row.context
if request is None:
request = row.parent.context.view.request request = row.parent.context.view.request
voc = self.vocabulary voc = self.vocabulary
if isinstance(voc, basestring): if isinstance(voc, basestring):
@ -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):
if row is not None:
source = voc(row.parent.context) 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]

View file

@ -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

View file

@ -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')

View file

@ -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)