diff --git a/CHANGES.txt b/CHANGES.txt
index c53cd7c..f905435 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -3,6 +3,23 @@ Change Log
$Id$
+1.0
+---
+
+New features
+
+- work items (work in progress): activate by adding option
+ ``action.portlet:createWorkitem`` to type; work items listing is shown
+ automatically in standard concept view.
+- my work items: a query view (``userworkitems.html``); assign the query
+ to the person as a standard child
+
+Bug fixes
+
+- external collection: now works correctly (without creating empty files
+ in the var directory); resource type of generated object controlled by
+ mime type; automatically executes transformation steps on media assets
+
0.9
---
diff --git a/browser/common.py b/browser/common.py
index 77b8080..d089a79 100644
--- a/browser/common.py
+++ b/browser/common.py
@@ -235,6 +235,10 @@ class BaseView(GenericView, I18NView):
def typePredicate(self):
return self.conceptManager.getTypePredicate()
+ @Lazy
+ def defaultPredicate(self):
+ return self.conceptManager.getDefaultPredicate()
+
@Lazy
def url(self):
return absoluteURL(self.context, self.request)
diff --git a/browser/loops.css b/browser/loops.css
index 77a90fd..b3e2d7a 100644
--- a/browser/loops.css
+++ b/browser/loops.css
@@ -80,6 +80,11 @@ table.listing td.checkbox {
padding-right: 2px;
}
+table.listing td.headline {
+ font-weight: bold;
+ border: 1px solid lightgrey;
+}
+
table.listing-details td {
white-space: normal;
border: 1px solid lightgrey;
diff --git a/organize/tracking/report.py b/organize/tracking/report.py
index 27db79f..d0cbc18 100644
--- a/organize/tracking/report.py
+++ b/organize/tracking/report.py
@@ -196,6 +196,17 @@ class TrackDetails(BaseView):
self.view = view
self.track = track
+ @Lazy
+ def month(self):
+ ts = datetime.fromtimestamp(self.track.timeStamp)
+ return formatAsMonth(date(ts.year, ts.month, 1))
+
+ @property
+ def monthChanged(self):
+ result = self.view.lastMonth != self.month
+ self.view.lastMonth = self.month
+ return result
+
@Lazy
def authentication(self):
return component.getUtility(IAuthentication)
diff --git a/organize/work/browser.py b/organize/work/browser.py
index b038b1a..fa871db 100644
--- a/organize/work/browser.py
+++ b/organize/work/browser.py
@@ -17,7 +17,7 @@
#
"""
-View class(es) for change tracks.
+View class(es) for work items.
$Id$
"""
@@ -33,6 +33,7 @@ from zope.traversing.api import getName
from cybertools.browser.action import actions
from cybertools.organize.interfaces import IWorkItems
from loops.browser.action import DialogAction
+from loops.browser.concept import ConceptView
from loops.browser.form import ObjectForm, EditObject
from loops.browser.node import NodeView
from loops.organize.party import getPersonForUser
@@ -45,18 +46,35 @@ from loops.util import _
work_macros = ViewPageTemplateFile('work_macros.pt')
-class WorkItemsView(NodeView):
+# work item collections
+
+class BaseWorkItemsView(object):
+
+ columns = set(['Task', 'User', 'Title', 'Start', 'End', 'Duration'])
+
+ lastMonth = None
def __init__(self, context, request):
self.context = context
self.request = request
+ @Lazy
+ def work_macros(self):
+ return work_macros.macros
+
@Lazy
def workItems(self):
ts = self.loopsRoot.getRecordManager().get('work')
if ts is not None:
return IWorkItems(ts)
+
+class WorkItemsView(BaseWorkItemsView, NodeView):
+ """ Standard view for showing work items for a node's target.
+ """
+
+ columns = set(['User', 'Title', 'Start', 'End', 'Duration'])
+
@Lazy
def allWorkItems(self):
result = []
@@ -69,7 +87,33 @@ class WorkItemsView(NodeView):
return result
+class UserWorkItems(BaseWorkItemsView, ConceptView):
+ """ A query view showing work items for a person, the query's parent.
+ """
+
+ columns = set(['Task', 'Title', 'Start', 'End', 'Duration'])
+
+ @property
+ def macro(self):
+ return self.work_macros['userworkitems']
+
+ @Lazy
+ def allWorkItems(self):
+ workItems = self.workItems
+ if self.workItems is None:
+ return []
+ result = []
+ for target in self.context.getParents([self.defaultPredicate]):
+ for wi in workItems.query(userName=util.getUidForObject(target)):
+ result.append(WorkItemDetails(self, wi))
+ return result
+
+
+# single work items
+
class WorkItemDetails(TrackDetails):
+ """ Render a single work item.
+ """
@Lazy
def description(self):
@@ -81,13 +125,30 @@ class WorkItemDetails(TrackDetails):
@Lazy
def end(self):
- return self.formatTimeStamp(self.track.end)[-5:]
+ ts = self.formatTimeStamp(self.track.end)
+ return ts and ts[-5:] or ''
+
+ @Lazy
+ def duration(self):
+ return self.formatTimeDelta(self.track.duration)
+
+ @Lazy
+ def effort(self):
+ return self.formatTimeDelta(self.track.effort)
+
+ def formatTimeDelta(self, value):
+ if not value:
+ return ''
+ h, m = divmod(int(value) / 60, 60)
+ return '%02i:%02i' % (h, m)
class WorkItemView(BaseTrackView):
+ """ Show a single work item in the management view.
+ """
- pass
+# forms and form controllers
class CreateWorkItemForm(ObjectForm, BaseTrackView):
diff --git a/organize/work/configure.zcml b/organize/work/configure.zcml
index 1ce74ab..0b19ec6 100644
--- a/organize/work/configure.zcml
+++ b/organize/work/configure.zcml
@@ -28,6 +28,14 @@
class="loops.organize.work.browser.WorkItemsView"
permission="zope.View" />
+
+
+
+
+ tal:define="work nocall:view/workItems"
+ tal:condition="work/allWorkItems">
Work Items
+ tal:define="work nocall:work|nocall:view/workItems;">
- Title |
- User |
- Start |
- End |
+
+ Task |
+
-
+
+
+ 2009-01 |
-
- Title |
-
- John |
-
- 2007-03-30 |
-
- 2007-03-30 |
+ repeat['row'].odd() and 'even' or 'odd'">
+ 2007-03-30 |
+ 2007-03-30 |
+ 2:30 |
+
+ Task |
+
+ John |
+ Title |
+
+
+ Work Items
+
+
+
+
+