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>
</a>
</td>
<td><span tal:content="related/typeTitle"
<td class="center"><span tal:content="related/typeTitle"
i18n:translate="">Type</span></td>
<td><span tal:replace="related/modified">Type</span></td>
<td><span tal:replace="related/creators">Type</span></td>
@ -162,7 +162,8 @@
<div tal:content="related/title">Resource Title</div>
</a>
</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">
<td class="center"
tal:define="versionId related/versionId">

View file

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

View file

@ -269,7 +269,9 @@ class TrackDetails(BaseView):
@Lazy
def user(self):
userName = self.track.userName
return self.getUserForUserName(self.track.userName)
def getUserForUserName(self, userName):
obj = util.getObjectForUid(userName)
if obj is None:
try:
@ -292,9 +294,6 @@ class TrackDetails(BaseView):
@Lazy
def timeStamp(self):
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'):
if not ts:

View file

@ -30,6 +30,7 @@ from zope.app.pagetemplate import ViewPageTemplateFile
from zope.traversing.browser import absoluteURL
from zope.traversing.api import getName
from cybertools.ajax import innerHtml
from cybertools.browser.action import actions
from cybertools.organize.interfaces import IWorkItems
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.node import NodeView
from loops.organize.party import getPersonForUser
from loops.organize.stateful.browser import StateAction
from loops.organize.tracking.browser import BaseTrackView
from loops.organize.tracking.report import TrackDetails
from loops import util
@ -50,7 +52,7 @@ work_macros = ViewPageTemplateFile('work_macros.pt')
class BaseWorkItemsView(object):
columns = set(['Task', 'User', 'Title', 'Start', 'End', 'Duration'])
columns = set(['Task', 'User', 'Title', 'Start', 'End', 'Duration', 'Info'])
lastMonth = lastDay = None
@ -85,7 +87,7 @@ class WorkItemsView(BaseWorkItemsView, NodeView):
""" 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
def allWorkItems(self):
@ -105,7 +107,7 @@ class UserWorkItems(BaseWorkItemsView, ConceptView):
""" 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
def macro(self):
@ -152,12 +154,73 @@ class WorkItemDetails(TrackDetails):
def effort(self):
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):
if not value:
return ''
h, m = divmod(int(value) / 60, 60)
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):
""" Show a single work item in the management view.
@ -174,6 +237,21 @@ class CreateWorkItemForm(ObjectForm, BaseTrackView):
def macro(self):
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
def defaultDate(self):
return time.strftime('%Y-%m-%d')
@ -185,6 +263,13 @@ class CreateWorkItemForm(ObjectForm, 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
def personId(self):
p = getPersonForUser(self.context, self.request)
@ -229,7 +314,10 @@ class CreateWorkItem(EditObject, BaseTrackView):
action, data = self.processForm()
if not action:
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)
url = self.view.virtualTargetUrl + '?version=this'
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
def parseTime(s):

View file

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

View file

@ -5,8 +5,8 @@
<!-- listings -->
<metal:work define-macro="workitems"
tal:define="work nocall:view/workItems"
tal:condition="work/allWorkItems">
tal:define="work nocall:view/workItems"
tal:condition="work/allWorkItems">
<br />
<h2 i18n:translate="">Work Items</h2>
<metal:workitems define-macro="workitems_listing"
@ -14,7 +14,7 @@
<table class="listing">
<tr>
<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"
tal:content="column"
i18n:translate="">Task</th>
@ -39,6 +39,11 @@
tal:content="row/user/title">John</a></td>
<td tal:content="row/track/title"
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>
</tal:workitem>
</table>
@ -60,20 +65,22 @@
dojoType="dijit.form.Form">
<input type="hidden" name="form.action" value="create_workitem" />
<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>
<label i18n:translate="" for="title">Title</label>
<div>
<input name="title" id="title"
<input name="title" id="title" style="width: 60em"
dojoType="dijit.form.ValidationTextBox" required
style="width: 60em" /></div>
tal:attributes="value view/title" /></div>
</div>
<div>
<label i18n:translate="" for="description">Description</label>
<div>
<textarea name="description" cols="80" rows="4" id="description"
dojoType="dijit.form.SimpleTextarea"
style="width: 60em"></textarea></div>
dojoType="dijit.form.SimpleTextarea" style="width: 60em"
tal:content="view/description"></textarea></div>
</div>
<div>
<label i18n:translate="" for="start-end">Start - End</label>
@ -115,4 +122,61 @@
</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>

View file

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