improve display of rows in work items listing
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@3106 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
be71f62a6e
commit
ed35bcf5af
7 changed files with 147 additions and 21 deletions
17
CHANGES.txt
17
CHANGES.txt
|
@ -3,6 +3,23 @@ Change Log
|
||||||
|
|
||||||
$Id$
|
$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
|
0.9
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -235,6 +235,10 @@ class BaseView(GenericView, I18NView):
|
||||||
def typePredicate(self):
|
def typePredicate(self):
|
||||||
return self.conceptManager.getTypePredicate()
|
return self.conceptManager.getTypePredicate()
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def defaultPredicate(self):
|
||||||
|
return self.conceptManager.getDefaultPredicate()
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def url(self):
|
def url(self):
|
||||||
return absoluteURL(self.context, self.request)
|
return absoluteURL(self.context, self.request)
|
||||||
|
|
|
@ -80,6 +80,11 @@ table.listing td.checkbox {
|
||||||
padding-right: 2px;
|
padding-right: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table.listing td.headline {
|
||||||
|
font-weight: bold;
|
||||||
|
border: 1px solid lightgrey;
|
||||||
|
}
|
||||||
|
|
||||||
table.listing-details td {
|
table.listing-details td {
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
border: 1px solid lightgrey;
|
border: 1px solid lightgrey;
|
||||||
|
|
|
@ -196,6 +196,17 @@ class TrackDetails(BaseView):
|
||||||
self.view = view
|
self.view = view
|
||||||
self.track = track
|
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
|
@Lazy
|
||||||
def authentication(self):
|
def authentication(self):
|
||||||
return component.getUtility(IAuthentication)
|
return component.getUtility(IAuthentication)
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
"""
|
"""
|
||||||
View class(es) for change tracks.
|
View class(es) for work items.
|
||||||
|
|
||||||
$Id$
|
$Id$
|
||||||
"""
|
"""
|
||||||
|
@ -33,6 +33,7 @@ from zope.traversing.api import getName
|
||||||
from cybertools.browser.action import actions
|
from cybertools.browser.action import actions
|
||||||
from cybertools.organize.interfaces import IWorkItems
|
from cybertools.organize.interfaces import IWorkItems
|
||||||
from loops.browser.action import DialogAction
|
from loops.browser.action import DialogAction
|
||||||
|
from loops.browser.concept import ConceptView
|
||||||
from loops.browser.form import ObjectForm, EditObject
|
from loops.browser.form import ObjectForm, EditObject
|
||||||
from loops.browser.node import NodeView
|
from loops.browser.node import NodeView
|
||||||
from loops.organize.party import getPersonForUser
|
from loops.organize.party import getPersonForUser
|
||||||
|
@ -45,18 +46,35 @@ from loops.util import _
|
||||||
work_macros = ViewPageTemplateFile('work_macros.pt')
|
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):
|
def __init__(self, context, request):
|
||||||
self.context = context
|
self.context = context
|
||||||
self.request = request
|
self.request = request
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def work_macros(self):
|
||||||
|
return work_macros.macros
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def workItems(self):
|
def workItems(self):
|
||||||
ts = self.loopsRoot.getRecordManager().get('work')
|
ts = self.loopsRoot.getRecordManager().get('work')
|
||||||
if ts is not None:
|
if ts is not None:
|
||||||
return IWorkItems(ts)
|
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
|
@Lazy
|
||||||
def allWorkItems(self):
|
def allWorkItems(self):
|
||||||
result = []
|
result = []
|
||||||
|
@ -69,7 +87,33 @@ class WorkItemsView(NodeView):
|
||||||
return result
|
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):
|
class WorkItemDetails(TrackDetails):
|
||||||
|
""" Render a single work item.
|
||||||
|
"""
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def description(self):
|
def description(self):
|
||||||
|
@ -81,13 +125,30 @@ class WorkItemDetails(TrackDetails):
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def end(self):
|
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):
|
class WorkItemView(BaseTrackView):
|
||||||
|
""" Show a single work item in the management view.
|
||||||
|
"""
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
# forms and form controllers
|
||||||
|
|
||||||
class CreateWorkItemForm(ObjectForm, BaseTrackView):
|
class CreateWorkItemForm(ObjectForm, BaseTrackView):
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,14 @@
|
||||||
class="loops.organize.work.browser.WorkItemsView"
|
class="loops.organize.work.browser.WorkItemsView"
|
||||||
permission="zope.View" />
|
permission="zope.View" />
|
||||||
|
|
||||||
|
<zope:adapter
|
||||||
|
name="userworkitems.html"
|
||||||
|
for="loops.interfaces.IConcept
|
||||||
|
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||||
|
provides="zope.interface.Interface"
|
||||||
|
factory="loops.organize.work.browser.UserWorkItems"
|
||||||
|
permission="zope.View" />
|
||||||
|
|
||||||
<browser:page
|
<browser:page
|
||||||
name="create_workitem.html"
|
name="create_workitem.html"
|
||||||
for="loops.interfaces.INode"
|
for="loops.interfaces.INode"
|
||||||
|
|
|
@ -2,37 +2,57 @@
|
||||||
<!-- $Id$ -->
|
<!-- $Id$ -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- listings -->
|
||||||
|
|
||||||
<metal:work define-macro="workitems"
|
<metal:work define-macro="workitems"
|
||||||
tal:define="workItems nocall:view/workItems"
|
tal:define="work nocall:view/workItems"
|
||||||
tal:condition="workItems/allWorkItems">
|
tal:condition="work/allWorkItems">
|
||||||
<br />
|
<br />
|
||||||
<h2 i18n:translate="">Work Items</h2>
|
<h2 i18n:translate="">Work Items</h2>
|
||||||
<metal:workitems define-macro="workitems_listing"
|
<metal:workitems define-macro="workitems_listing"
|
||||||
tal:define="workItems nocall:workItems|nocall:view/workItems;">
|
tal:define="work nocall:work|nocall:view/workItems;">
|
||||||
<table class="listing">
|
<table class="listing">
|
||||||
<tr>
|
<tr>
|
||||||
<th i18n:translate="">Title</th>
|
<tal:colheader repeat="column python:
|
||||||
<th i18n:translate="">User</th>
|
('Start', 'End', 'Duration', 'Task', 'User', 'Title')">
|
||||||
<th i18n:translate="">Start</th>
|
<th tal:condition="python: column in work.columns"
|
||||||
<th i18n:translate="">End</th>
|
tal:content="column"
|
||||||
|
i18n:translate="">Task</th>
|
||||||
|
</tal:colheader>
|
||||||
</tr>
|
</tr>
|
||||||
<tal:workitem tal:repeat="workItem workItems/allWorkItems">
|
<tal:workitem tal:repeat="row work/allWorkItems">
|
||||||
|
<tr tal:condition="row/monthChanged">
|
||||||
|
<td class="headline"
|
||||||
|
tal:attributes="colspan python: len(work.columns)"
|
||||||
|
tal:content="row/month">2009-01</td></tr>
|
||||||
<tr tal:attributes="class python:
|
<tr tal:attributes="class python:
|
||||||
repeat['workItem'].odd() and 'even' or 'odd'">
|
repeat['row'].odd() and 'even' or 'odd'">
|
||||||
<td>
|
<td class="nowrap center" tal:content="row/start">2007-03-30</td>
|
||||||
<span tal:content="workItem/track/title">Title</span></td>
|
<td class="nowrap center" tal:content="row/end">2007-03-30</td>
|
||||||
<td>
|
<td class="nowrap center" tal:content="row/duration">2:30</td>
|
||||||
<span tal:replace="workItem/user/title">John</span></td>
|
<td tal:condition="python: 'Task' in work.columns">
|
||||||
<td class="nowrap">
|
<a tal:attributes="href row/objectData/url"
|
||||||
<span tal:replace="workItem/start">2007-03-30</span></td>
|
tal:content="row/objectData/title">Task</a></td>
|
||||||
<td class="nowrap">
|
<td tal:condition="python: 'User' in work.columns">
|
||||||
<span tal:replace="workItem/end">2007-03-30</span></td>
|
<a tal:attributes="href row/user/url"
|
||||||
|
tal:content="row/user/title">John</a></td>
|
||||||
|
<td tal:content="row/track/title"
|
||||||
|
tal:attributes="title row/track/description">Title</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tal:workitem>
|
</tal:workitem>
|
||||||
</table>
|
</table>
|
||||||
</metal:workitems>
|
</metal:workitems>
|
||||||
</metal:work>
|
</metal:work>
|
||||||
|
|
||||||
|
<metal:work define-macro="userworkitems"
|
||||||
|
tal:define="work nocall:item">
|
||||||
|
<br />
|
||||||
|
<h2 i18n:translate="" tal:content="item/title">Work Items</h2>
|
||||||
|
<metal:workitems use-macro="item/work_macros/workitems_listing" />
|
||||||
|
</metal:work>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- forms -->
|
||||||
|
|
||||||
<metal:block define-macro="create_workitem">
|
<metal:block define-macro="create_workitem">
|
||||||
<form method="post" id="addWorkitem_form" class="dialog"
|
<form method="post" id="addWorkitem_form" class="dialog"
|
||||||
|
|
Loading…
Add table
Reference in a new issue