diff --git a/browser/skin/lobo/lobo.css b/browser/skin/lobo/lobo.css index fdac5d1..f9b572f 100644 --- a/browser/skin/lobo/lobo.css +++ b/browser/skin/lobo/lobo.css @@ -262,6 +262,12 @@ table.records th, table.records td { border: 1px solid lightgrey; } +table.report { + position: relative; + z-index: 99; + background: white; +} + table.report th { border-bottom: 1px solid #bbbbbb; font-weight: bold; diff --git a/expert/browser/report.pt b/expert/browser/report.pt index d5a2fb9..90ae0f2 100755 --- a/expert/browser/report.pt +++ b/expert/browser/report.pt @@ -141,7 +141,14 @@ - + diff --git a/expert/field.py b/expert/field.py index e5e32d4..9abfa13 100644 --- a/expert/field.py +++ b/expert/field.py @@ -119,7 +119,7 @@ class IntegerField(Field): class DateField(Field): - fieldType='date', + fieldType='date' format = ('date', 'short') renderer = cssClass = 'center' dbtype = 'date' @@ -192,6 +192,8 @@ class WorkItemStateField(Field): class VocabularyField(Field): vocabulary = None + sourceList = None + fieldType = 'selection' def getDisplayValue(self, row): value = self.getRawValue(row) @@ -202,9 +204,11 @@ class VocabularyField(Field): if str(item['token']) == str(value): return item['title'] - def getVocabularyItems(self, row): - context = row.context - request = row.parent.context.view.request + def getVocabularyItems(self, row=None, context=None, request=None): + if context is None: + context = row.context + if request is None: + request = row.parent.context.view.request voc = self.vocabulary if isinstance(voc, basestring): terms = self.getVocabularyTerms(voc, context, request) @@ -213,7 +217,10 @@ class VocabularyField(Field): voc = voc.splitlines() return [dict(token=t, title=t) for t in voc if t.strip()] 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) if terms is not None: termsList = [terms.getTerm(value) for value in source] diff --git a/organize/work/README.txt b/organize/work/README.txt index 2d0fcc6..c9d82bf 100644 --- a/organize/work/README.txt +++ b/organize/work/README.txt @@ -232,7 +232,7 @@ The user interface is a ReportConceptView subclass that is directly associated w ... print 08/12/28 19:00 20:15 {'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': [...]} >>> results.totals.data @@ -247,8 +247,8 @@ Export of work data >>> output = reportView() >>> print output - Day;Start;End;Task;Party;Title;Duration;Effort;State - 08/12/28;19:00;20:15;loops Development;john;;1.2500;0.2500;finished + Day;Start;End;Task;Party;Title;LA;Effort;State + 08/12/28;19:00;20:15;loops Development;john;;;0.2500;finished Meeting Minutes diff --git a/organize/work/report.py b/organize/work/report.py index 9ad8e27..4967d4e 100644 --- a/organize/work/report.py +++ b/organize/work/report.py @@ -39,11 +39,13 @@ from loops.common import adapted, baseObject from loops.expert.browser.export import ResultsConceptCSVExport from loops.expert.browser.report import ReportConceptView 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 TrackDateField, TrackTimeField, TrackDateTimeField from loops.expert.field import WorkItemStateField from loops.expert.report import ReportInstance +from loops.table import DataTableSourceBinder, DataTableSourceListByValue from loops import util @@ -114,6 +116,28 @@ class PartyStateField(StateField): 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): days = 7 opt = context.view.typeOptions('workitem_dayfrom_default') @@ -193,7 +217,10 @@ partyState = PartyStateField('partyState', u'Party State', cssClass='center', statesDefinition='contact_states', 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 @@ -233,7 +260,7 @@ class WorkRow(BaseRow): attributeHandlers = dict(day=getDay, dayStart=getStart, dayEnd=getEnd, dayFrom=getDay, dayTo=getDay, - duration=getDuration, effort=getEffort,) + duration=getDuration, effort=getEffort) class WorkReportInstance(ReportInstance): @@ -246,9 +273,11 @@ class WorkReportInstance(ReportInstance): fields = Jeep((dayFrom, dayTo, tasks, day, timeStart, timeEnd, task, party, workTitle, #description, - duration, effort, state)) + activity, + #duration, + effort, state)) - userSettings = (dayFrom, dayTo, party) + userSettings = (dayFrom, dayTo, party, activity) defaultOutputFields = fields defaultSortCriteria = (day, timeStart,) defaultStates = ('done', 'done_x', 'finished') diff --git a/table.py b/table.py index 2daac11..8a3f77a 100644 --- a/table.py +++ b/table.py @@ -138,22 +138,6 @@ def getRowValue(k, v): def getRowValueWithKey(k, v): 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): @@ -170,3 +154,32 @@ class DataTableSourceList(object): def __len__(self): 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) +