provide work item infos: icon with link, info popup

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@3149 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2009-01-14 09:44:16 +00:00
parent b5b4270f58
commit 6ff94ad004
7 changed files with 198 additions and 26 deletions

View file

@ -101,7 +101,7 @@
<span tal:replace="related/title">Resource Title</span> <span tal:replace="related/title">Resource Title</span>
</a> </a>
</td> </td>
<td><span tal:content="related/typeTitle" <td class="center"><span tal:content="related/typeTitle"
i18n:translate="">Type</span></td> i18n:translate="">Type</span></td>
<td><span tal:replace="related/modified">Type</span></td> <td><span tal:replace="related/modified">Type</span></td>
<td><span tal:replace="related/creators">Type</span></td> <td><span tal:replace="related/creators">Type</span></td>
@ -162,7 +162,8 @@
<div tal:content="related/title">Resource Title</div> <div tal:content="related/title">Resource Title</div>
</a> </a>
</td> </td>
<td><span tal:replace="related/longTypeTitle">Type</span></td> <td class="center">
<span tal:replace="related/longTypeTitle">Type</span></td>
<tal:version tal:condition="view/useVersioning"> <tal:version tal:condition="view/useVersioning">
<td class="center" <td class="center"
tal:define="versionId related/versionId"> tal:define="versionId related/versionId">

View file

@ -117,6 +117,7 @@ class NodeView(BaseView):
if not IUnauthenticatedPrincipal.providedBy(self.request.principal): if not IUnauthenticatedPrincipal.providedBy(self.request.principal):
mi = self.controller.memberInfo mi = self.controller.memberInfo
title = mi.title.value or _(u'Personal Informations') title = mi.title.value or _(u'Personal Informations')
url=None
obj = mi.get('object') obj = mi.get('object')
if obj is not None: if obj is not None:
query = self.conceptManager.get('personal_info') query = self.conceptManager.get('personal_info')
@ -125,11 +126,11 @@ class NodeView(BaseView):
url = self.getUrlForTarget(obj.value) url = self.getUrlForTarget(obj.value)
else: else:
url = self.getUrlForTarget(query) url = self.getUrlForTarget(query)
cm.register('portlet_right', 'personal', title=title, cm.register('portlet_right', 'personal', title=title,
subMacro=node_macros.macros['personal'], subMacro=node_macros.macros['personal'],
icon='cybertools.icons/user.png', icon='cybertools.icons/user.png',
url=url, url=url,
priority=10) priority=10)
# force early portlet registrations by target by setting up target view # force early portlet registrations by target by setting up target view
self.virtualTarget self.virtualTarget

View file

@ -269,7 +269,9 @@ class TrackDetails(BaseView):
@Lazy @Lazy
def user(self): def user(self):
userName = self.track.userName return self.getUserForUserName(self.track.userName)
def getUserForUserName(self, userName):
obj = util.getObjectForUid(userName) obj = util.getObjectForUid(userName)
if obj is None: if obj is None:
try: try:
@ -292,9 +294,6 @@ class TrackDetails(BaseView):
@Lazy @Lazy
def timeStamp(self): def timeStamp(self):
return self.formatTimeStamp(self.track.timeStamp) return self.formatTimeStamp(self.track.timeStamp)
#value = datetime.fromtimestamp(self.track.timeStamp)
#return format.formatDate(value, 'dateTime', self.timeStampFormat,
# self.view.languageInfo.language)
def formatTimeStamp(self, ts, f='dateTime'): def formatTimeStamp(self, ts, f='dateTime'):
if not ts: if not ts:

View file

@ -30,6 +30,7 @@ from zope.app.pagetemplate import ViewPageTemplateFile
from zope.traversing.browser import absoluteURL from zope.traversing.browser import absoluteURL
from zope.traversing.api import getName from zope.traversing.api import getName
from cybertools.ajax import innerHtml
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
@ -37,6 +38,7 @@ 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
from loops.organize.stateful.browser import StateAction
from loops.organize.tracking.browser import BaseTrackView from loops.organize.tracking.browser import BaseTrackView
from loops.organize.tracking.report import TrackDetails from loops.organize.tracking.report import TrackDetails
from loops import util from loops import util
@ -50,7 +52,7 @@ work_macros = ViewPageTemplateFile('work_macros.pt')
class BaseWorkItemsView(object): class BaseWorkItemsView(object):
columns = set(['Task', 'User', 'Title', 'Start', 'End', 'Duration']) columns = set(['Task', 'User', 'Title', 'Start', 'End', 'Duration', 'Info'])
lastMonth = lastDay = None lastMonth = lastDay = None
@ -85,7 +87,7 @@ class WorkItemsView(BaseWorkItemsView, NodeView):
""" Standard view for showing work items for a node's target. """ Standard view for showing work items for a node's target.
""" """
columns = set(['User', 'Title', 'Day', 'Start', 'End', 'Duration']) columns = set(['User', 'Title', 'Day', 'Start', 'End', 'Duration', 'Info'])
@Lazy @Lazy
def allWorkItems(self): def allWorkItems(self):
@ -105,7 +107,7 @@ class UserWorkItems(BaseWorkItemsView, ConceptView):
""" A query view showing work items for a person, the query's parent. """ A query view showing work items for a person, the query's parent.
""" """
columns = set(['Task', 'Title', 'Day', 'Start', 'End', 'Duration']) columns = set(['Task', 'Title', 'Day', 'Start', 'End', 'Duration', 'Info'])
@property @property
def macro(self): def macro(self):
@ -152,12 +154,73 @@ class WorkItemDetails(TrackDetails):
def effort(self): def effort(self):
return self.formatTimeDelta(self.track.effort) return self.formatTimeDelta(self.track.effort)
@Lazy
def startDay(self):
return self.formatTimeStamp(self.track.timeStamp, 'date')
@Lazy
def created(self):
return self.formatTimeStamp(self.track.created, 'dateTime')
def formatTimeDelta(self, value): def formatTimeDelta(self, value):
if not value: if not value:
return '' return ''
h, m = divmod(int(value) / 60, 60) h, m = divmod(int(value) / 60, 60)
return '%02i:%02i' % (h, m) return '%02i:%02i' % (h, m)
@Lazy
def isLastInRun(self):
currentWorkItems = list(self.view.workItems.query(runId=self.track.runId))
return self.track == currentWorkItems[-1]
def actions(self):
info = DialogAction(self.view,
description=_(u'Information about this work item.'),
viewName='workitem_info.html',
dialogName='',
icon='cybertools.icons/info.png',
cssClass='icon-action',
page=self.view.nodeView,
target=self.object,
addParams=dict(id=self.track.__name__))
actions = [info, WorkItemStateAction(self)]
if self.isLastInRun:
self.view.registerDojoDateWidget()
self.view.registerDojoNumberWidget()
actions.append(DialogAction(self.view,
description=_(u'Create a work item.'),
viewName='create_workitem.html',
dialogName='',
icon='edit.gif',
cssClass='icon-action',
page=self.view.nodeView,
target=self.object,
addParams=dict(id=self.track.__name__)))
return actions
class WorkItemInfo(NodeView):
""" Provides info box.
"""
__call__ = innerHtml
@property
def macro(self):
return work_macros.macros['workitem_info']
@Lazy
def dialog_name(self):
return self.request.get('dialog', 'workitem_info')
@Lazy
def track(self):
id = self.request.form.get('id')
if id is not None:
workItems = self.loopsRoot.getRecordManager()['work']
track = workItems.get(id)
return WorkItemDetails(self, track)
class WorkItemView(BaseTrackView): class WorkItemView(BaseTrackView):
""" Show a single work item in the management view. """ Show a single work item in the management view.
@ -174,6 +237,21 @@ class CreateWorkItemForm(ObjectForm, BaseTrackView):
def macro(self): def macro(self):
return self.template.macros['create_workitem'] return self.template.macros['create_workitem']
@Lazy
def track(self):
id = self.request.form.get('id')
if id is not None:
workItems = self.loopsRoot.getRecordManager()['work']
return workItems.get(id)
@Lazy
def title(self):
return self.track is not None and self.track.title or u''
@Lazy
def description(self):
return self.track is not None and self.track.description or u''
@Lazy @Lazy
def defaultDate(self): def defaultDate(self):
return time.strftime('%Y-%m-%d') return time.strftime('%Y-%m-%d')
@ -185,6 +263,13 @@ class CreateWorkItemForm(ObjectForm, BaseTrackView):
class CreateWorkItem(EditObject, BaseTrackView): class CreateWorkItem(EditObject, BaseTrackView):
@Lazy
def track(self):
id = self.request.form.get('id')
if id is not None:
workItems = self.loopsRoot.getRecordManager()['work']
return workItems.get(id)
@Lazy @Lazy
def personId(self): def personId(self):
p = getPersonForUser(self.context, self.request) p = getPersonForUser(self.context, self.request)
@ -229,7 +314,10 @@ class CreateWorkItem(EditObject, BaseTrackView):
action, data = self.processForm() action, data = self.processForm()
if not action: if not action:
return True return True
wi = workItems.add(util.getUidForObject(self.object), self.personId) if self.track is not None:
wi = self.track
else:
wi = workItems.add(util.getUidForObject(self.object), self.personId)
wi.doAction(action, self.personId, **data) wi.doAction(action, self.personId, **data)
url = self.view.virtualTargetUrl + '?version=this' url = self.view.virtualTargetUrl + '?version=this'
self.request.response.redirect(url) self.request.response.redirect(url)
@ -247,6 +335,19 @@ actions.register('createWorkitem', 'portlet', DialogAction,
) )
class WorkItemStateAction(StateAction):
cssClass = 'icon-action'
@Lazy
def stateful(self):
return self.view.track
@Lazy
def description(self):
return _(self.stateObject.title)
# auxiliary functions # auxiliary functions
def parseTime(s): def parseTime(s):

View file

@ -49,6 +49,12 @@
factory="loops.organize.work.browser.CreateWorkItem" factory="loops.organize.work.browser.CreateWorkItem"
permission="zope.View" /> permission="zope.View" />
<browser:page
name="workitem_info.html"
for="loops.interfaces.INode"
class="loops.organize.work.browser.WorkItemInfo"
permission="zope.View" />
<!-- setup --> <!-- setup -->
<zope:adapter factory="loops.organize.work.setup.SetupManager" <zope:adapter factory="loops.organize.work.setup.SetupManager"

View file

@ -5,8 +5,8 @@
<!-- listings --> <!-- listings -->
<metal:work define-macro="workitems" <metal:work define-macro="workitems"
tal:define="work nocall:view/workItems" tal:define="work nocall:view/workItems"
tal:condition="work/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"
@ -14,7 +14,7 @@
<table class="listing"> <table class="listing">
<tr> <tr>
<tal:colheader repeat="column python: <tal:colheader repeat="column python:
('Day', 'Start', 'End', 'Duration', 'Task', 'User', 'Title')"> ('Day', 'Start', 'End', 'Duration', 'Task', 'User', 'Title', 'Info')">
<th tal:condition="python: column in work.columns" <th tal:condition="python: column in work.columns"
tal:content="column" tal:content="column"
i18n:translate="">Task</th> i18n:translate="">Task</th>
@ -39,6 +39,11 @@
tal:content="row/user/title">John</a></td> tal:content="row/user/title">John</a></td>
<td tal:content="row/track/title" <td tal:content="row/track/title"
tal:attributes="title row/track/description">Title</td> tal:attributes="title row/track/description">Title</td>
<td class="nowrap">
<tal:actions repeat="action row/actions">
<metal:action use-macro="action/macro" />
</tal:actions>
</td>
</tr> </tr>
</tal:workitem> </tal:workitem>
</table> </table>
@ -60,20 +65,22 @@
dojoType="dijit.form.Form"> dojoType="dijit.form.Form">
<input type="hidden" name="form.action" value="create_workitem" /> <input type="hidden" name="form.action" value="create_workitem" />
<input type="hidden" name="workitem.action" value="finish" /> <input type="hidden" name="workitem.action" value="finish" />
<input type="hidden" name="id"
tal:attributes="value request/form/id|nothing" />
<div class="heading" i18n:translate="">Add Work Item</div> <div class="heading" i18n:translate="">Add Work Item</div>
<div> <div>
<label i18n:translate="" for="title">Title</label> <label i18n:translate="" for="title">Title</label>
<div> <div>
<input name="title" id="title" <input name="title" id="title" style="width: 60em"
dojoType="dijit.form.ValidationTextBox" required dojoType="dijit.form.ValidationTextBox" required
style="width: 60em" /></div> tal:attributes="value view/title" /></div>
</div> </div>
<div> <div>
<label i18n:translate="" for="description">Description</label> <label i18n:translate="" for="description">Description</label>
<div> <div>
<textarea name="description" cols="80" rows="4" id="description" <textarea name="description" cols="80" rows="4" id="description"
dojoType="dijit.form.SimpleTextarea" dojoType="dijit.form.SimpleTextarea" style="width: 60em"
style="width: 60em"></textarea></div> tal:content="view/description"></textarea></div>
</div> </div>
<div> <div>
<label i18n:translate="" for="start-end">Start - End</label> <label i18n:translate="" for="start-end">Start - End</label>
@ -115,4 +122,61 @@
</metal:block> </metal:block>
<metal:info define-macro="workitem_info"
tal:define="item nocall:view/track">
<table class="object_info" width="400">
<tr>
<td colspan="2"><h2 i18n:translate="">Work Item Information</h2><br /></td>
</tr>
<tr>
<td><span i18n:translate="">Title</span>:</td>
<td tal:content="item/track/title"></td>
</tr>
<tr>
<td valign="top"><span i18n:translate="">Description</span>:</td>
<td tal:content="item/description"></td>
</tr>
<tr>
<td><span i18n:translate="">Party</span>:</td>
<td tal:content="item/user/title"></td>
</tr>
<tr>
<td><span i18n:translate="">Task</span>:</td>
<td tal:content="item/object/title"></td>
</tr>
<tr>
<td><span i18n:translate="">Start - End</span>:</td>
<td><span tal:content="item/startDay" />
<span tal:content="item/start" /> -
<span tal:content="item/end" /></td>
</tr>
<tr>
<td><span i18n:translate="">Duration/Effort</span>:</td>
<td><span tal:content="item/duration" /> /
<span tal:content="item/effort" /></td>
</tr>
<tr>
<td valign="top"><span i18n:translate="">Comment</span>:</td>
<td tal:content="item/track/comment"></td>
</tr>
<tr tal:define="state item/track/getStateObject">
<td><span i18n:translate="">State</span>:</td>
<td tal:content="state/title"></td>
</tr>
<tr>
<td><span i18n:translate="">Created</span>:</td>
<td><span tal:content="item/created" />
(<span tal:content="python:
item.getUserForUserName(item.track.creator)['title']" />)</td>
</tr>
<tr>
<td colspan="2"><br />
<input type="button" value="Close" onclick="closeDialog()"
i18n:attributes="value" />
</td>
</tr>
</table>
</metal:info>
</html> </html>

View file

@ -80,10 +80,10 @@
tal:attributes="src icon/src" /> tal:attributes="src icon/src" />
<div tal:content="row/title" /></a> <div tal:content="row/title" /></a>
</td> </td>
<td i18n:translate="" <td i18n:translate="" class="center"
tal:content="row/longTypeTitle|row/typeTitle">Type</td> tal:content="row/longTypeTitle|row/typeTitle">Type</td>
<tal:version condition="view/useVersioning"> <tal:version condition="view/useVersioning">
<td style="text-align: center" <td class="center"
tal:define="versionId row/versionId|string:"> tal:define="versionId row/versionId|string:">
<a href="#" <a href="#"
tal:content="versionId" tal:content="versionId"
@ -91,12 +91,12 @@
tal:attributes="href string:${view/url}/.target${row/uniqueId}?loops.viewName=listversions">1.1</a> tal:attributes="href string:${view/url}/.target${row/uniqueId}?loops.viewName=listversions">1.1</a>
</td> </td>
</tal:version> </tal:version>
<td style="text-align: right; white-space: nowrap"> <td class="nowrap number">
<span tal:replace="row/context/sizeForDisplay|string:">Size</span> <span tal:replace="row/context/sizeForDisplay|string:">Size</span>
</td> </td>
<td><span tal:replace="row/modified">modified</span></td> <td><span tal:replace="row/modified">modified</span></td>
<td><span tal:replace="row/creators">John</span></td> <td><span tal:replace="row/creators">John</span></td>
<td style="white-space: nowrap" <td class="nowrap center"
tal:define="target nocall:row; tal:define="target nocall:row;
style nothing" style nothing"
tal:condition="view/showObjectActions"> tal:condition="view/showObjectActions">