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