merge branch master

This commit is contained in:
Helmut Merz 2012-09-05 16:17:15 +02:00
commit 17012129b8
23 changed files with 565 additions and 171 deletions

View file

@ -45,6 +45,7 @@ from cybertools.composer.schema.grid.field import grid_macros
from cybertools.composer.schema.interfaces import ISchemaFactory from cybertools.composer.schema.interfaces import ISchemaFactory
from cybertools.composer.schema.browser.common import schema_macros, schema_edit_macros from cybertools.composer.schema.browser.common import schema_macros, schema_edit_macros
from cybertools.composer.schema.schema import FormState from cybertools.composer.schema.schema import FormState
from cybertools.meta.interfaces import IOptions
from cybertools.stateful.interfaces import IStateful from cybertools.stateful.interfaces import IStateful
from cybertools.typology.interfaces import IType, ITypeManager from cybertools.typology.interfaces import IType, ITypeManager
from cybertools.util.format import toUnicode from cybertools.util.format import toUnicode
@ -739,6 +740,13 @@ class EditConcept(EditObject):
return obj.getParentRelations(predicates=predicates, parent=concept) return obj.getParentRelations(predicates=predicates, parent=concept)
def assignConcept(self, obj, concept, predicate): def assignConcept(self, obj, concept, predicate):
if IOptions(adapted(concept.conceptType)).children_append:
sibRelations = concept.getChildRelations()
if sibRelations:
maxOrder = max([r.order for r in sibRelations])
if maxOrder > 0:
return obj.assignParent(concept, predicate,
order=maxOrder+1)
obj.assignParent(concept, predicate) obj.assignParent(concept, predicate)
def deassignConcept(self, obj, concept, predicates): def deassignConcept(self, obj, concept, predicates):

View file

@ -526,6 +526,12 @@ div.comment {
background-color: #eeeeff; background-color: #eeeeff;
} }
tr.agenda-item-headline td,
tr.agenda-item-headline td a,
tr.agenda-item-headline td a[href] {
color: white;
}
/* dojo stuff */ /* dojo stuff */
.dijitDialog { .dijitDialog {

View file

@ -125,22 +125,18 @@ function setConceptTypeForComboBox(typeId, cbId) {
} }
var dialog; var dialog;
var dialogName;
function objectDialog(dlgName, url) { function objectDialog(dlgName, url) {
dojo.require('dijit.Dialog'); dojo.require('dijit.Dialog');
dojo.require('dojo.parser'); dojo.require('dojo.parser');
dojo.require('dijit.form.FilteringSelect'); dojo.require('dijit.form.FilteringSelect');
dojo.require('dojox.data.QueryReadStore'); dojo.require('dojox.data.QueryReadStore');
if (dialogName == undefined || dialogName != dlgName || dialogName == '') { if (dialog != undefined) {
if (dialog != undefined) { dialog.destroyRecursive();
dialog.destroyRecursive();
}
dialogName = dlgName;
dialog = new dijit.Dialog({
href: url
}, dojo.byId('dialog.' + dlgName));
} }
dialog = new dijit.Dialog({
href: url
}, dojo.byId('dialog.' + dlgName));
dialog.show(); dialog.show();
} }

View file

@ -510,6 +510,12 @@ img.notselected {
text-align: right; text-align: right;
} }
/* work */
.work_event {
background-color: #f3f3ff;
}
/* lobo layout-specific classes */ /* lobo layout-specific classes */
.legend { .legend {
@ -591,6 +597,10 @@ div.comment {
/* calendar, work items */ /* calendar, work items */
.MinutesAndAgendaTitles a[href] {
color: white;
}
.today { .today {
color: #444488; color: #444488;
font-weight: bold; font-weight: bold;

View file

@ -50,6 +50,18 @@ class Base(object):
for p in self.context.getParents([self.isPartOfPredicate]): for p in self.context.getParents([self.isPartOfPredicate]):
return self.nodeView.getViewForTarget(p) return self.nodeView.getViewForTarget(p)
@Lazy
def tabview(self):
if self.editable:
return 'index.html'
class BookOverview(Base, ConceptView):
@Lazy
def macro(self):
return book_template.macros['book']
class SectionView(Base, ConceptView): class SectionView(Base, ConceptView):
@ -58,17 +70,24 @@ class SectionView(Base, ConceptView):
return book_template.macros['section'] return book_template.macros['section']
@Lazy @Lazy
def tabview(self): def documentTypeType(self):
if self.editable: return self.conceptManager['documenttype']
return 'index.html'
@Lazy
def sectionType(self):
return self.conceptManager['section']
def getCssClassForResource(self, r): def getCssClassForResource(self, r):
documentType = self.conceptManager['documenttype']
for c in r.context.getConcepts([self.defaultPredicate]): for c in r.context.getConcepts([self.defaultPredicate]):
if c.conceptType == documentType: if c.conceptType == self.documentTypeType:
return getName(c) return getName(c)
return 'textelement' return 'textelement'
def getParentsForResource(self, r):
for c in r.context.getConcepts([self.defaultPredicate]):
if c != self.context and c.conceptType != self.documentTypeType:
yield c
# layout parts - probably obsolete: # layout parts - probably obsolete:

View file

@ -17,6 +17,14 @@
<!-- Views --> <!-- Views -->
<zope:adapter
name="book_overview"
for="loops.interfaces.IConcept
loops.browser.skin.Lobo"
provides="zope.interface.Interface"
factory="loops.compound.book.browser.BookOverview"
permission="zope.View" />
<zope:adapter <zope:adapter
name="section_view" name="section_view"
for="loops.interfaces.IConcept for="loops.interfaces.IConcept

View file

@ -2,7 +2,7 @@ type(u'documenttype', u'Dokumentenart', options=u'qualifier:assign',
viewName=u'') viewName=u'')
# book types # book types
type(u'book', u'Buch', viewName=u'', typeInterface=u'', type(u'book', u'Buch', viewName=u'book_overview', typeInterface=u'',
options=u'action.portlet:create_subtype,edit_concept') options=u'action.portlet:create_subtype,edit_concept')
#type(u'page', u'Seite', viewName=u'page_layout', #type(u'page', u'Seite', viewName=u'page_layout',
# typeInterface=u'loops.compound.book.interfaces.IPage', # typeInterface=u'loops.compound.book.interfaces.IPage',

View file

@ -1,32 +1,51 @@
<html i18n:domain="loops"> <html i18n:domain="loops">
<metal:book define-macro="book">
<metal:info use-macro="view/concept_macros/concepttitle" />
<div tal:repeat="related item/children">
<h3>
<a tal:attributes="href python:view.getUrlForTarget(related)"
tal:content="related/title" /></h3>
<div tal:content="structure related/renderedDescription" />
</div>
</metal:book>
<metal:section define-macro="section"> <metal:section define-macro="section">
<metal:info use-macro="view/concept_macros/concepttitle" /> <metal:info use-macro="view/concept_macros/concepttitle" />
<div tal:repeat="related item/resources"> <div tal:repeat="related item/resources">
<div class="object-actions" style="padding-top: 0" <div class="span-4">
tal:define="url python:view.getUrlForTarget(related.context)" <div tal:attributes="class python:
tal:condition="related/editable"> item.getCssClassForResource(related)"
<a i18n:translate="" i18n:attributes="title" tal:content="structure related/render" />
title="Edit" </div>
tal:define="targetUid python:view.getUidForObject(related.context); <div class="span-2 last" style="padding-top: 0.4em">
url <div class="object-actions" style="padding-top: 0"
string:$url/edit_object.html?version=this&targetUid=$targetUid" tal:define="url python:view.getUrlForTarget(related.context)"
tal:attributes="href url; tal:condition="related/editable">
onclick string:objectDialog('edit', '$url');; <a i18n:translate="" i18n:attributes="title"
return false"> title="Edit"
<img tal:attributes="src tal:define="targetUid python:view.getUidForObject(related.context);
string:$resourceBase/cybertools.icons/vcard_edit.png" /></a> url
<a i18n:translate="" i18n:attributes="title" string:$url/edit_object.html?version=this&targetUid=$targetUid"
title="Edit with external editor." tal:attributes="href url;
tal:condition="related/xeditable" onclick string:objectDialog('edit', '$url');;
tal:attributes="href string:$url/external_edit?version=this"> return false">
<img tal:attributes="src <img tal:attributes="src
string:$resourceBase/cybertools.icons/vcard_edit.png" /></a>
<a i18n:translate="" i18n:attributes="title"
title="Edit with external editor."
tal:condition="related/xeditable"
tal:attributes="href string:$url/external_edit?version=this">
<img tal:attributes="src
string:$resourceBase/cybertools.icons/application_edit.png" /></a> string:$resourceBase/cybertools.icons/application_edit.png" /></a>
</div> </div>
<div tal:attributes="class python: <div tal:repeat="parent python:item.getParentsForResource(related)">
item.getCssClassForResource(related)" <a tal:content="parent/title"
tal:content="structure related/render" /> tal:attributes="href python:view.getUrlForTarget(parent)" />
</div>
</div>
</div> </div>
</metal:section> </metal:section>

View file

@ -68,9 +68,19 @@
</metal:right> </metal:right>
<metal:state define-macro="state">
<tal:column define=" value python:col.getDisplayValue(row)">
<img tal:attributes="src string:$resourceBase${value/icon};
alt value/title;
title value/title" />
</tal:column>
</metal:state>
<metal:target define-macro="target"> <metal:target define-macro="target">
<tal:column define="value python:col.getDisplayValue(row)"> <tal:column define="value python:col.getDisplayValue(row)">
<a tal:omit-tag="python:not getattr(item, 'showLinks', True) or not value['url']" <a tal:omit-tag="python:
not getattr(item, 'showLinks', True) or not value['url']"
tal:attributes="href value/url" tal:attributes="href value/url"
tal:content="value/title" /> tal:content="value/title" />
</tal:column> </tal:column>

View file

@ -28,6 +28,7 @@ from zope.schema.interfaces import IVocabularyFactory, IContextSourceBinder
from cybertools.composer.report.field import Field as BaseField from cybertools.composer.report.field import Field as BaseField
from cybertools.composer.report.field import TableCellStyle from cybertools.composer.report.field import TableCellStyle
from cybertools.composer.report.result import ResultSet from cybertools.composer.report.result import ResultSet
from cybertools.stateful.interfaces import IStateful, IStatesDefinition
from cybertools.util.date import timeStamp2Date from cybertools.util.date import timeStamp2Date
from loops.common import baseObject from loops.common import baseObject
from loops.expert.report import ReportInstance from loops.expert.report import ReportInstance
@ -115,6 +116,23 @@ class DateField(Field):
return value.isoformat()[:10] return value.isoformat()[:10]
class StateField(Field):
statesDefinition = 'workItemStates'
renderer = 'state'
def getDisplayValue(self, row):
if IStateful.providedBy(row.context):
stf = row.context
else:
stf = component.getAdapter(row.context, IStateful,
name=self.statesDefinition)
stateObject = stf.getStateObject()
icon = stateObject.icon or 'led%s.png' % stateObject.color
return dict(title=util._(stateObject.title),
icon='cybertools.icons/' + icon)
class VocabularyField(Field): class VocabularyField(Field):
vocabulary = None vocabulary = None

Binary file not shown.

View file

@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: $Id$\n" "Project-Id-Version: $Id$\n"
"POT-Creation-Date: 2007-05-22 12:00 CET\n" "POT-Creation-Date: 2007-05-22 12:00 CET\n"
"PO-Revision-Date: 2012-07-21 12:00 CET\n" "PO-Revision-Date: 2012-08-20 12:00 CET\n"
"Last-Translator: Helmut Merz <helmutm@cy55.de>\n" "Last-Translator: Helmut Merz <helmutm@cy55.de>\n"
"Language-Team: loops developers <helmutm@cy55.de>\n" "Language-Team: loops developers <helmutm@cy55.de>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@ -254,6 +254,18 @@ msgstr "Termin bearbeiten"
msgid "Modify follow-up event." msgid "Modify follow-up event."
msgstr "Folgetermin bearbeiten" msgstr "Folgetermin bearbeiten"
msgid "Create Agenda Item..."
msgstr "Tagesordnungspunkt anlegen..."
msgid "Create a new agenda item."
msgstr "Einen neuen Tagesordnungspunkt anlegen."
msgid "Edit Agenda Item..."
msgstr "Tagesordnungspunkt bearbeiten..."
msgid "Modify agenda item."
msgstr "Tagesordnungspunkt bearbeiten"
msgid "Create Task..." msgid "Create Task..."
msgstr "Aufgabe anlegen..." msgstr "Aufgabe anlegen..."
@ -275,6 +287,12 @@ msgstr "Eine neues Projekt anlegen."
msgid "Create Work Item..." msgid "Create Work Item..."
msgstr "Aktivität anlegen..." msgstr "Aktivität anlegen..."
msgid "Create a work item for this object."
msgstr "Eine Aktivität zu diesem Objekt anlegen."
msgid "Add Work Item"
msgstr "Aktivität anlegen/bearbeiten"
msgid "Edit Video..." msgid "Edit Video..."
msgstr "Video bearbeiten..." msgstr "Video bearbeiten..."
@ -296,6 +314,9 @@ msgstr "Besprechungsprotokoll für dieses Objekt anzeigen."
msgid "Download Meeting Minutes" msgid "Download Meeting Minutes"
msgstr "Besprechungsprotokoll generieren" msgstr "Besprechungsprotokoll generieren"
msgid "Copy Agenda Items"
msgstr "Tagesordnungspunkte kopieren"
msgid "Participants" msgid "Participants"
msgstr "Teilnehmer" msgstr "Teilnehmer"
@ -303,7 +324,7 @@ msgid "The names of the persons taking part in the event."
msgstr "Die Namen der Personen, die an der Besprechung teilnehmen." msgstr "Die Namen der Personen, die an der Besprechung teilnehmen."
msgid "label_responsible" msgid "label_responsible"
msgstr "Vortragender" msgstr "Vortragende/r"
msgid "desc_responsible" msgid "desc_responsible"
msgstr "Person, die diesen Tagesordnungpunkt vertritt." msgstr "Person, die diesen Tagesordnungpunkt vertritt."
@ -315,10 +336,19 @@ msgid "desc_discussion"
msgstr "Diskussion" msgstr "Diskussion"
msgid "label_consequences" msgid "label_consequences"
msgstr "Schlussfolgerungen" msgstr "Schlussfolgerung"
msgid "desc_consequences" msgid "desc_consequences"
msgstr "Schlussfolgerungen" msgstr "Schlussfolgerung"
msgid "header_workitems"
msgstr "Aufgaben"
msgid "header_responsible"
msgstr "zuständig"
msgid "header_deadline"
msgstr "Termin"
msgid "Task/Action" msgid "Task/Action"
msgstr "Aufgabe" msgstr "Aufgabe"

View file

@ -39,6 +39,7 @@ from loops.browser.node import NodeView
from loops.common import adapted, baseObject from loops.common import adapted, baseObject
from loops.concept import Concept from loops.concept import Concept
from loops.organize.work.meeting import MeetingMinutes from loops.organize.work.meeting import MeetingMinutes
from loops.organize.tracking.report import TrackDetails
from loops.setup import addAndConfigureObject from loops.setup import addAndConfigureObject
from loops.util import _ from loops.util import _
from loops import util from loops import util
@ -79,6 +80,24 @@ actions.register('editFollowUpEvent', 'portlet', TargetAction,
prerequisites=['registerDojoDateWidget'], prerequisites=['registerDojoDateWidget'],
) )
actions.register('createAgendaItem', 'portlet', DialogAction,
title=_(u'Create Agenda Item...'),
description=_(u'Create a new agenda item.'),
viewName='create_concept.html',
dialogName='createAgendaItem',
typeToken='.loops/concepts/agendaitem',
fixedType=True,
innerForm='inner_concept_form.html',
prerequisites=['registerDojoDateWidget'],
)
actions.register('editAgendaItem', 'portlet', DialogAction,
title=_(u'Edit Agenda Item...'),
description=_(u'Modify agenda item.'),
viewName='edit_concept.html',
dialogName='editAgendaItem',
)
class Events(ConceptView): class Events(ConceptView):
@ -317,9 +336,21 @@ class CreateFollowUpEvent(CreateConcept, BaseFollowUpController):
result = super(CreateFollowUpEvent, self).update() result = super(CreateFollowUpEvent, self).update()
form = self.request.form form = self.request.form
toBeAssigned = form.get('cb_select_tasks') or [] toBeAssigned = form.get('cb_select_tasks') or []
for uid in toBeAssigned: taskId = newTask = None
task = util.getObjectForUid(uid) workItems = self.view.loopsRoot.getRecordManager()['work']
self.createFollowUpTask(adapted(task)) for id in sorted(toBeAssigned):
if not '.' in id:
taskId = id
task = util.getObjectForUid(id)
newTask = self.createFollowUpTask(adapted(task))
else:
tId, trackId = id.split('.')
if tId == taskId:
track = workItems.get(trackId)
if track is not None:
td = TrackDetails(self.view, track)
newTId = self.view.getUidForObject(newTask)
track.doAction('move', td.personId, task=newTId)
return result return result
def createFollowUpTask(self, source): def createFollowUpTask(self, source):
@ -333,12 +364,13 @@ class CreateFollowUpEvent(CreateConcept, BaseFollowUpController):
conceptType=taskType, conceptType=taskType,
title=source.title, title=source.title,
description=source.description, description=source.description,
responsible=source.start, responsible=source.responsible,
discussion=source.discussion, discussion=source.discussion,
consequences=source.consequences) consequences=source.consequences)
stask.assignChild(newTask, self.followsPredicate) stask.assignChild(newTask, self.followsPredicate)
for rel in stask.getParentRelations(): for rel in stask.getParentRelations():
if rel.predicate != self.view.typePredicate: if rel.predicate not in (
self.view.typePredicate, self.followsPredicate):
if rel.first == bevt: if rel.first == bevt:
parent = self.object parent = self.object
else: else:

View file

@ -58,13 +58,14 @@
<form metal:define-macro="create_followup_event" method="post" <form metal:define-macro="create_followup_event" method="post"
id="dialog_form" class="dialog" id="dialog_form" class="dialog"
dojoType="dijit.form.Form" dojoType="dijit.form.Form"
tal:define="item nocall:item|nocall:view"> tal:define="item nocall:item|nocall:view;
showState python:True">
<h2 tal:content="view/title" <h2 tal:content="view/title"
i18n:translate="" /> i18n:translate="" />
<input type="hidden" name="form.action" <input type="hidden" name="form.action"
tal:attributes="value view/form_action" /> tal:attributes="value view/form_action" />
<metal:data use-macro="view/fieldRenderers/fields" /> <metal:data use-macro="view/fieldRenderers/fields" />
<h3 i18n:translate="">Tasks</h3> <br />
<tal:tasks define="report item/reportInstance; <tal:tasks define="report item/reportInstance;
reportView nocall:item; reportView nocall:item;
results reportView/results; results reportView/results;

View file

@ -186,7 +186,7 @@ class IAgendaItem(ILoopsAdapter):
missing_value=u'', missing_value=u'',
required=False) required=False)
concequences = schema.Text( consequences = schema.Text(
title=_(u'label_consequences'), title=_(u'label_consequences'),
description=_(u'desc_consequences.'), description=_(u'desc_consequences.'),
default=u'', default=u'',

View file

@ -60,7 +60,6 @@ class AgendaItem(AdapterBase):
implements(IAgendaItem) implements(IAgendaItem)
_adapterAttributes = AdapterBase._adapterAttributes
_contextAttributes = list(IAgendaItem) _contextAttributes = list(IAgendaItem)

View file

@ -174,8 +174,8 @@ So we use the PersonWorkItems view, assigning john to the query.
>>> work = PersonWorkItems(query, TestRequest(form=input)) >>> work = PersonWorkItems(query, TestRequest(form=input))
>>> work.listWorkItems() >>> work.listWorkItems()
[<WorkItem ['36', 2, '33', '2009-01-19 09:00', 'planned']: [<WorkItem ['36', 2, '33', '2009-01-19 09:00', 'planned']:
{'start': 1232352000, 'created': ..., 'title': u'Install Zope', {'title': u'Install Zope', 'created': ..., 'end': 1232352000,
'creator': '33'}>] 'start': 1232352000, 'creator': '33'}>]
Work Reports Work Reports
@ -228,7 +228,8 @@ 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 finished {'url': '.../home/.33', 'title': u'john'} 01:15 00:15
{'icon': 'cybertools.icons/ledgreen.png', 'title': u'finished'}
>>> results.totals.data >>> results.totals.data
{'effort': 900} {'effort': 900}
@ -248,7 +249,7 @@ Let's start with creating an a event and assigning it a task.
... typeInterface=IEvent) ... typeInterface=IEvent)
>>> tAgendaItem = addAndConfigureObject(concepts, Concept, 'agendaitem', >>> tAgendaItem = addAndConfigureObject(concepts, Concept, 'agendaitem',
... title=u'AgendaItem', conceptType=concepts.getTypeConcept(), ... title=u'AgendaItem', conceptType=concepts.getTypeConcept(),
... typeInterface=IEvent) ... typeInterface=IAgendaItem)
>>> ev01 = addAndConfigureObject(concepts, Concept, 'ev01', >>> ev01 = addAndConfigureObject(concepts, Concept, 'ev01',
... title=u'loops Meeting', conceptType=tEvent) ... title=u'loops Meeting', conceptType=tEvent)

View file

@ -33,13 +33,16 @@ from zope.traversing.api import getName, getParent
from cybertools.ajax import innerHtml from cybertools.ajax import innerHtml
from cybertools.browser.action import actions from cybertools.browser.action import actions
from cybertools.meta.interfaces import IOptions
from cybertools.organize.interfaces import IWorkItems from cybertools.organize.interfaces import IWorkItems
from cybertools.organize.work import workItemTypes
from cybertools.tracking.btree import getTimeStamp from cybertools.tracking.btree import getTimeStamp
from cybertools.util import format from cybertools.util import format
from loops.browser.action import DialogAction from loops.browser.action import DialogAction
from loops.browser.concept import ConceptView 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.common import adapted
from loops.organize.party import getPersonForUser from loops.organize.party import getPersonForUser
from loops.organize.stateful.browser import StateAction from loops.organize.stateful.browser import StateAction
from loops.organize.tracking.browser import BaseTrackView from loops.organize.tracking.browser import BaseTrackView
@ -60,6 +63,10 @@ class WorkItemDetails(TrackDetails):
""" Render a single work item. """ Render a single work item.
""" """
@Lazy
def workItemType(self):
return self.track.getWorkItemType()
@Lazy @Lazy
def description(self): def description(self):
return self.track.description return self.track.description
@ -72,13 +79,19 @@ class WorkItemDetails(TrackDetails):
def descriptionFormatted(self): def descriptionFormatted(self):
return format.nl2br(self.description) return format.nl2br(self.description)
@Lazy
def deadline(self):
return self.formatTimeStamp(self.track.deadline, 'date')
@Lazy @Lazy
def start(self): def start(self):
return self.formatTimeStamp(self.track.start, 'time') result = self.formatTimeStamp(self.track.start, 'time')
return result != '00:00' and result or ''
@Lazy @Lazy
def end(self): def end(self):
return self.formatTimeStamp(self.track.end, 'time') result = self.formatTimeStamp(self.track.end, 'time')
return result != '00:00' and result or ''
@Lazy @Lazy
def duration(self): def duration(self):
@ -340,6 +353,32 @@ class CreateWorkItemForm(ObjectForm, BaseTrackView):
def description(self): def description(self):
return self.track.description or u'' return self.track.description or u''
@Lazy
def workItemType(self):
return self.track.getWorkItemType() or self.workItemTypes[0]
@Lazy
def workItemTypes(self):
task = self.task
if task is None:
task = self.target
options = IOptions(adapted(task.conceptType))
typeNames = options.workitem_types
if typeNames:
return [workItemTypes[name] for name in typeNames]
return workItemTypes
@Lazy
def showTypes(self):
return len(self.workItemTypes) != 1
@Lazy
def deadline(self):
ts = self.track.deadline# or getTimeStamp()
if ts:
return time.strftime('%Y-%m-%d', time.localtime(ts))
return ''
@Lazy @Lazy
def date(self): def date(self):
ts = self.track.start or getTimeStamp() ts = self.track.start or getTimeStamp()
@ -367,11 +406,21 @@ class CreateWorkItemForm(ObjectForm, BaseTrackView):
@Lazy @Lazy
def actions(self): def actions(self):
result = [dict(name=t.name, title=t.title) result = [dict(name=t.name, title=t.title)
for t in self.track.getAvailableTransitions()] for t in self.track.getAvailableTransitions()
#if t.name != 'delegate' or if t.name in self.workItemType.actions and
# checkPermission('loops.ManageSite', self.context)] t.name not in self.hiddenActions]
#and (t.name != 'delegate' or
# checkPermission('loops.ManageSite', self.context))]
return result return result
@Lazy
def hiddenActions(self):
task = self.task
if task is None:
task = self.target
options = IOptions(adapted(task.conceptType))
return options.hidden_workitem_actions or []
def getTypesParamsForFilteringSelect(self, types=['person']): def getTypesParamsForFilteringSelect(self, types=['person']):
result = [] result = []
for t in types: for t in types:
@ -387,7 +436,14 @@ class CreateWorkItemForm(ObjectForm, BaseTrackView):
return [dict(name=util.getUidForObject(p), title=p.title) return [dict(name=util.getUidForObject(p), title=p.title)
for p in persons] for p in persons]
taskTypes = ['task', 'event'] taskTypes = ['task', 'event', 'agendaitem']
@Lazy
def followUpTask(self):
pred = self.conceptManager.get('follows')
if pred is not None and self.task is not None:
for t in self.task.getChildren([pred]):
return t
@Lazy @Lazy
def x_tasks(self): def x_tasks(self):
@ -452,17 +508,16 @@ class CreateWorkItem(EditObject, BaseTrackView):
v = form.get(k) v = form.get(k)
if v: if v:
result[k] = v result[k] = v
for k in ('title', 'description', 'comment'): for k in ('workItemType', 'title', 'description', 'comment'):
setValue(k) setValue(k)
if action == 'delegate': if action == 'delegate':
setValue('party') setValue('party')
if action == 'move': if action == 'move':
setValue('task') setValue('task')
result['deadline'] = parseDate(form.get('deadline'))
startDate = form.get('start_date', '').strip() startDate = form.get('start_date', '').strip()
startTime = form.get('start_time', '').strip().replace('T', '') or '00:00:00' startTime = form.get('start_time', '').strip().replace('T', '') or '00:00:00'
endTime = form.get('end_time', '').strip().replace('T', '') or '00:00:00' endTime = form.get('end_time', '').strip().replace('T', '') or '00:00:00'
#print '***', startDate, startTime, endTime
#if startDate and startTime:
if startDate: if startDate:
result['start'] = parseDateTime('T'.join((startDate, startTime))) result['start'] = parseDateTime('T'.join((startDate, startTime)))
result['end'] = parseDateTime('T'.join((startDate, endTime))) result['end'] = parseDateTime('T'.join((startDate, endTime)))

View file

@ -115,6 +115,7 @@
name="meeting_minutes.doc" name="meeting_minutes.doc"
for="loops.interfaces.IConceptSchema" for="loops.interfaces.IConceptSchema"
class="loops.organize.work.meeting.MeetingMinutesDocument" class="loops.organize.work.meeting.MeetingMinutesDocument"
attribute="embed"
permission="zope.View" /> permission="zope.View" />
<!-- setup --> <!-- setup -->

View file

@ -4,7 +4,8 @@
<div metal:define-macro="content" <div metal:define-macro="content"
tal:define="report item/reportInstance; tal:define="report item/reportInstance;
reportView nocall:item; reportView nocall:item;
results reportView/results"> results reportView/results;
showState python:True">
<div tal:attributes="class string:content-$level;"> <div tal:attributes="class string:content-$level;">
<metal:block use-macro="view/concept_macros/concepttitle" /> <metal:block use-macro="view/concept_macros/concepttitle" />
<metal:block use-macro="view/concept_macros/conceptfields" /> <metal:block use-macro="view/concept_macros/conceptfields" />
@ -19,91 +20,189 @@
</div> </div>
<div metal:define-macro="document" <metal:doc define-macro="document"
tal:define="item nocall:view; tal:define="item nocall:view;
report item/reportInstance; report item/reportInstance;
reportView nocall:item; reportView nocall:item;
results reportView/results; results reportView/results;
fields results/context/fields"> fields results/context/fields;
<metal:header use-macro="item/macros/header" /> showCheckboxes nothing;
<metal:results use-macro="reportView/resultsRenderer" /> showState nothing">
</div> <div class ="WordSection1">
<div align="center">
<table class="MsoTableGrid" width="98%" cellpadding="0" cellspacing="0">
<div metal:define-macro="header" <metal:header use-macro="item/macros/header" />
tal:define="row results/first"> <metal:header use-macro="item/macros/rows" />
<h1 i18n:translate="">Meeting Minutes</h1> </table>
<h2 tal:define="col fields/eventTitle"> </div>
<metal:col use-macro="python:item.getColumnRenderer(col)" /></h2>
<div>
<span tal:define="col fields/eventStart">
<metal:col use-macro="python:item.getColumnRenderer(col)" /></span> -
<span tal:define="col fields/eventEnd">
<metal:col use-macro="python:item.getColumnRenderer(col)" /></span>
</div> </div>
<div tal:define="col fields/eventDescription"> </metal:doc>
<metal:col use-macro="python:item.getColumnRenderer(col)" /></div>
</div>
<div metal:define-macro="results"> <metal:header define-macro="header"
tal:define="row results/first">
<tr style="background-color: #777777; color: white">
<td colspan="4">
<div tal:define="col fields/eventTitle"
class="MinutesAndAgendaTitles">
<metal:col use-macro="python:item.getColumnRenderer(col)" /></div>
<div tal:define="col fields/eventDescription"
class="MinutesAndAgendaTitles">
<metal:col use-macro="python:item.getColumnRenderer(col)" /></div>
</td>
</tr>
<tr style="background-color: #eeeeee">
<td colspan="2">
<span tal:define="col fields/eventDate">
<metal:col use-macro="python:item.getColumnRenderer(col)" /></span>
</td>
<td colspan="2">
<span tal:define="col fields/eventStart">
<metal:col use-macro="python:item.getColumnRenderer(col)" /></span> -
<span tal:define="col fields/eventEnd">
<metal:col use-macro="python:item.getColumnRenderer(col)" /></span>
</td>
</tr>
<tr>
<td width="20%"
i18n:translate="">Participants</td>
<td colspan="3">
<span tal:define="col fields/participants">
<metal:col use-macro="python:item.getColumnRenderer(col)" /></span>
</td>
</tr>
</metal:header>
<metal:results define-macro="results">
<table class="report" <table class="report"
tal:define="showCheckboxes cb_name|nothing"> tal:define="showCheckboxes cb_name|nothing">
<tr> <metal:rows define-macro="rows">
<th tal:condition="showCheckboxes" <tr tal:condition="showCheckboxes">
style="border: 1px solid grey"> <th style="border: 1px solid grey; width: 5%">
<input type="checkbox" checked
tal:attributes="onclick
string:toggleCheckBoxes(this, '$cb_name:list')" /></th>
<th i18n:translate=""
style="border: 1px solid grey">Task/Action</th>
<th style="border: 1px solid grey"
i18n:translate="">Who?</th>
<th style="border: 1px solid grey"
i18n:translate="">When?</th>
<th style="border: 1px solid grey"
i18n:translate=""></th>
</tr>
<tal:task repeat="row results">
<tr tal:repeat="colname python: ('title', 'description',)">
<td tal:condition="showCheckboxes"
style="border: 1px solid grey">
<input type="checkbox" checked <input type="checkbox" checked
tal:condition="python:colname == 'title'" tal:attributes="onclick
tal:attributes="name string:$cb_name:list; string:toggleCheckBoxes(this, '$cb_name:list')" /></th>
value row/context/uid" /></td> <th colspan="4"
<td style="border: 1px solid grey" i18n:translate=""
tal:define="col report/fields/?colname" style="border: 1px solid grey">Copy Agenda Items</th>
tal:attributes="class col/cssClass"> <td tal:condition="showState"
style="border: 1px solid #777777" />
</tr>
<tr>
<td tal:condition="showCheckboxes" style="width: 2%">&nbsp;</td>
<td style="width: 15%">&nbsp;</td>
<td style="width: 53%">&nbsp;</td>
<td style="width: 20%">&nbsp;</td>
<td style="width: 12%">&nbsp;</td>
<td tal:condition="showState" style="width: 2%">&nbsp;</td>
</tr>
<tal:tasks repeat="row results">
<tal:task define="taskUid row/context/uid">
<tr class="agenda-item-headline"
style="background-color: #777777">
<td tal:condition="showCheckboxes"
style="border: 1px solid #777777" class="center">
<input type="checkbox" checked
tal:attributes="name string:$cb_name:list;
value taskUid" /></td>
<td colspan="4"
style="border: 1px solid #777777"
tal:define="col report/fields/title"
tal:attributes="class col/cssClass">
<div class="MinutesAndAgendaTitles">
<metal:column use-macro="python:
reportView.getColumnRenderer(col)" /></div>
</td>
<td tal:condition="showState"
style="border: 1px solid #777777" />
</tr>
<tal:item repeat="colname python:
('responsible', 'description', 'discussion', 'consequences')">
<tr>
<tal:field define="col report/fields/?colname">
<td style="border: 1px solid grey"
tal:condition="showCheckboxes"></td>
<td style="border: 1px solid grey; width: 15%"
tal:content="col/title"
i18n:translate=""></td>
<td colspan="3"
style="border: 1px solid grey; width: 85%"
tal:attributes="class col/cssClass">
<metal:column use-macro="python:
reportView.getColumnRenderer(col)" />
</td>
</tal:field>
<td tal:condition="showState"
style="border-right: 1px solid #777777" />
</tr>
</tal:item>
<tal:workitems define="col report/fields/workItems;
results python:col.getValue(row)"
condition="results/result">
<tr style="background-color: #eeeeee">
<td style="border: 1px solid grey"
tal:condition="showCheckboxes"></td>
<td colspan="2"
style="border: 1px solid grey; width: 68%"
i18n:translate="">header_workitems</td>
<td style="border: 1px solid grey; width: 20%"
i18n:translate="">header_responsible</td>
<td style="border: 1px solid grey; width: 12%" class="center"
i18n:translate="">header_deadline</td>
<td tal:condition="showState"
style="border: 1px solid #777777" />
</tr>
<metal:column use-macro="python: <metal:column use-macro="python:
reportView.getColumnRenderer(col)" /> reportView.getColumnRenderer(col)" />
</td> </tal:workitems>
<td style="border: 1px solid grey" /> </tal:task>
<td style="border: 1px solid grey" /> </tal:tasks>
<td style="border: 1px solid grey" /> </metal:rows>
</tr>
<tal:workitems define="col report/fields/workItems">
<metal:column use-macro="python:
reportView.getColumnRenderer(col)" />
</tal:workitems>
</tal:task>
</table> </table>
</div> </metal:results>
<div metal:define-macro="subreport" <metal:sub define-macro="subreport"
tal:define="results python:col.getValue(row)"> tal:define="fields results/displayedColumns">
<tr class="listing" tal:repeat="row results"> <tr class="listing" tal:repeat="row results">
<td tal:condition="showCheckboxes" <td tal:condition="showCheckboxes"
style="border: 1px solid grey" /> style="border: 1px solid grey" class="center">
<td tal:repeat="col results/displayedColumns" <input type="checkbox"
tal:define="trackId row/context/name"
tal:attributes="name string:$cb_name:list;
value string:$taskUid.$trackId;
checked row/isActive" />
</td>
<td colspan="2"
tal:define="col fields/title"
tal:attributes="class col/cssClass" tal:attributes="class col/cssClass"
style="border: 1px solid grey"> style="border: 1px solid grey; width: 68%">
<metal:column use-macro="python: <metal:column use-macro="python:
reportView.getColumnRenderer(col)" /> reportView.getColumnRenderer(col)" />
</td> </td>
<td tal:define="col fields/userName"
tal:attributes="class col/cssClass"
style="border: 1px solid grey; width: 20%">
<metal:column use-macro="python:
reportView.getColumnRenderer(col)" />
</td>
<td tal:define="col fields/deadline"
tal:attributes="class col/cssClass"
style="border: 1px solid grey; width: 12%">
<metal:column use-macro="python:
reportView.getColumnRenderer(col)" />
</td>
<tal:state condition="showState">
<td tal:define="col fields/state"
tal:attributes="class col/cssClass"
style="border: 1px solid grey; width: 12%">
<metal:column use-macro="python:
reportView.getColumnRenderer(col)" />
</td>
</tal:state>
</tr> </tr>
</div> </metal:sub>
</html> </html>

View file

@ -66,10 +66,14 @@ class MeetingMinutes(ResultsConceptView):
class MeetingMinutesDocument(WordDocument, MeetingMinutes): class MeetingMinutesDocument(WordDocument, MeetingMinutes):
isToplevel = True isToplevel = True
omitSectionElement = True
def __init__(self, context, request): def __init__(self, context, request):
MeetingMinutes.__init__(self, context, request) MeetingMinutes.__init__(self, context, request)
def __call__(self, *args, **kw):
return self.embed(*args, **kw)
@Lazy @Lazy
def macros(self): def macros(self):
return meeting_template.macros return meeting_template.macros

View file

@ -34,7 +34,7 @@ from cybertools.util.format import formatDate
from cybertools.util.jeep import Jeep from cybertools.util.jeep import Jeep
from loops.common import adapted, baseObject from loops.common import adapted, baseObject
from loops.expert.browser.report import ReportConceptView from loops.expert.browser.report import ReportConceptView
from loops.expert.field import Field, TargetField, DateField, \ from loops.expert.field import Field, TargetField, DateField, StateField, \
TextField, UrlField TextField, UrlField
from loops.expert.field import SubReport, SubReportField from loops.expert.field import SubReport, SubReportField
from loops.expert.report import ReportInstance from loops.expert.report import ReportInstance
@ -50,13 +50,6 @@ class WorkStatementView(ReportConceptView):
# fields # fields
class StateField(Field):
def getDisplayValue(self, row):
value = self.getValue(row)
return util._(value)
class TrackDateField(Field): class TrackDateField(Field):
fieldType = 'date' fieldType = 'date'
@ -66,7 +59,7 @@ class TrackDateField(Field):
def getValue(self, row): def getValue(self, row):
value = self.getRawValue(row) value = self.getRawValue(row)
if value is None: if not value:
return None return None
return timeStamp2Date(value) return timeStamp2Date(value)
@ -119,6 +112,10 @@ tasks = Field('tasks', u'Tasks',
# work report fields # work report fields
deadline = TrackDateField('deadline', u'Deadline',
description=u'The day the work has to be finished.',
cssClass='center',
executionSteps=['sort', 'output'])
dayFrom = TrackDateField('dayFrom', u'Start Day', dayFrom = TrackDateField('dayFrom', u'Start Day',
description=u'The first day from which to select work.', description=u'The first day from which to select work.',
fieldType='date', fieldType='date',
@ -161,6 +158,7 @@ effort = DurationField('effort', u'Effort',
state = StateField('state', u'State', state = StateField('state', u'State',
description=u'The state of the work.', description=u'The state of the work.',
cssClass='center', cssClass='center',
statesDefinition='workItemStates',
executionSteps=['query', 'output']) executionSteps=['query', 'output'])
@ -278,14 +276,17 @@ class WorkReportInstance(ReportInstance):
class MeetingMinutesWorkRow(WorkRow): class MeetingMinutesWorkRow(WorkRow):
pass @Lazy
def isActive(self):
return self.context.state not in (
'finished', 'closed', 'cancelled', 'moved')
class MeetingMinutesWork(WorkReportInstance, SubReport): class MeetingMinutesWork(WorkReportInstance, SubReport):
rowFactory = MeetingMinutesWorkRow rowFactory = MeetingMinutesWorkRow
fields = Jeep((workTitle, party, day, state)) #description, fields = Jeep((workTitle, party, deadline, state)) #description,
defaultOutputFields = fields defaultOutputFields = fields
defaultSortCriteria = (day,) defaultSortCriteria = (day,)
states = ('planned', 'accepted', 'running', 'done', states = ('planned', 'accepted', 'running', 'done',
@ -309,13 +310,20 @@ eventTitle = CalculatedField('eventTitle', u'Event Title',
eventDescription = CalculatedField('eventDescription', u'Event Description', eventDescription = CalculatedField('eventDescription', u'Event Description',
description=u'', description=u'',
executionSteps=(['header'])) executionSteps=(['header']))
eventDate = DateField('eventDate', u'Event Date',
description=u'',
format=('date', 'short'),
executionSteps=(['header']))
eventStart = DateField('eventStart', u'Event Start', eventStart = DateField('eventStart', u'Event Start',
description=u'', description=u'',
format=('dateTime', 'short'), format=('time', 'short'),
executionSteps=(['header'])) executionSteps=(['header']))
eventEnd = DateField('eventEnd', u'Event End', eventEnd = DateField('eventEnd', u'Event End',
description=u'', description=u'',
format=('dateTime', 'short'), format=('time', 'short'),
executionSteps=(['header']))
participants = CalculatedField('participants', u'Participants',
description=u'',
executionSteps=(['header'])) executionSteps=(['header']))
taskTitle = UrlField('title', u'Task Title', taskTitle = UrlField('title', u'Task Title',
description=u'The short description of the task.', description=u'The short description of the task.',
@ -325,6 +333,18 @@ taskDescription = TextField('description', u'Description',
description=u'The long description of the task.', description=u'The long description of the task.',
cssClass='header-2', cssClass='header-2',
executionSteps=['output']) executionSteps=['output'])
responsible = TextField('responsible', u'label_responsible',
description=u'Responsible.',
cssClass='header-2',
executionSteps=['output'])
discussion = TextField('discussion', u'label_discussion',
description=u'Discussion.',
cssClass='header-2',
executionSteps=['output'])
consequences = TextField('consequences', u'label_consequences',
description=u'Consequences.',
cssClass='header-2',
executionSteps=['output'])
workItems = SubReportField('workItems', u'Work Items', workItems = SubReportField('workItems', u'Work Items',
description=u'A list of work items belonging to the task.', description=u'A list of work items belonging to the task.',
reportFactory=MeetingMinutesWork, reportFactory=MeetingMinutesWork,
@ -345,6 +365,10 @@ class TaskRow(BaseRow):
def eventDescription(self): def eventDescription(self):
return self.event.description return self.event.description
@Lazy
def eventDate(self):
return self.event.start
@Lazy @Lazy
def eventStart(self): def eventStart(self):
return self.event.start return self.event.start
@ -353,8 +377,13 @@ class TaskRow(BaseRow):
def eventEnd(self): def eventEnd(self):
return self.event.end return self.event.end
@Lazy
def participants(self):
return self.event.participants
useRowProperty = BaseRow.useRowProperty useRowProperty = BaseRow.useRowProperty
attributeHandlers = dict( attributeHandlers = dict(
eventDate=useRowProperty,
eventStart=useRowProperty, eventStart=useRowProperty,
eventEnd=useRowProperty, eventEnd=useRowProperty,
) )
@ -367,8 +396,10 @@ class MeetingMinutes(WorkReportInstance):
rowFactory = TaskRow rowFactory = TaskRow
fields = Jeep((eventTitle, eventStart, eventEnd, eventDescription, fields = Jeep((eventTitle, eventDate, eventStart, eventEnd,
tasks, taskTitle, taskDescription, workItems)) eventDescription, participants,
tasks, taskTitle, responsible, taskDescription,
discussion, consequences, workItems))
defaultOutputFields = fields defaultOutputFields = fields
states = ('planned', 'accepted', 'done', 'done_x', 'finished') states = ('planned', 'accepted', 'done', 'done_x', 'finished')
taskTypeNames = ('agendaitem',) taskTypeNames = ('agendaitem',)

View file

@ -24,8 +24,8 @@
<td class="headline" <td class="headline"
tal:attributes="colspan python: len(work.columns)" tal:attributes="colspan python: len(work.columns)"
tal:content="row/month">2009-01</td></tr> tal:content="row/month">2009-01</td></tr>
<tr tal:attributes="class python: <tr tal:define="wiType row/workItemType"
(repeat['row'].odd() and 'even' or 'odd')"> tal:attributes="class wiType/indicator|nothing">
<td class="nowrap center" <td class="nowrap center"
tal:define="today python: row.isToday and ' today' or ''" tal:define="today python: row.isToday and ' today' or ''"
tal:attributes="title row/weekDay; tal:attributes="title row/weekDay;
@ -67,12 +67,29 @@
<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"
xx_dojoType="dijit.form.Form"> xx_dojoType="dijit.form.Form"
tal:define="workItemTypes view/workItemTypes;
workItemType view/workItemType">
<input type="hidden" name="form.action" value="create_workitem" /> <input type="hidden" name="form.action" value="create_workitem" />
<input type="hidden" name="id" <input type="hidden" name="id"
tal:attributes="value request/form/id|nothing" /> 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>
<tal:type condition="view/showTypes">
<label i18n:translate="" for="types">Work Item Type</label>
<select name="workItemType" id="types">
<option tal:repeat="type workItemTypes"
tal:attributes="value type/name;
selected python:
type.name == workItemType.name"
tal:content="type/title"
i18n:translate="" />
</select>
</tal:type>
<tal:type condition="not:view/showTypes">
<input type="hidden" name="workItemType"
tal:attributes="value python:workItemTypes[0].name" />
</tal:type>
<label i18n:translate="" for="title">Title</label> <label i18n:translate="" for="title">Title</label>
<div> <div>
<input name="title" id="title" style="width: 60em" <input name="title" id="title" style="width: 60em"
@ -108,7 +125,8 @@
name="party" id="input_party" name="party" id="input_party"
store="party_search_store" /> store="party_search_store" />
</span> </span>
<span id="target_task" style="display: none">&nbsp; <span id="target_task" style="display: none"
tal:condition="not:view/followUpTask">&nbsp;
<label i18n:translate="move_to_task" for="input_task" <label i18n:translate="move_to_task" for="input_task"
style="display: inline">to</label> style="display: inline">to</label>
<span dojoType="dojox.data.QueryReadStore" jsId="task_search_store" <span dojoType="dojox.data.QueryReadStore" jsId="task_search_store"
@ -121,30 +139,54 @@
name="task" id="input_task" name="task" id="input_task"
store="task_search_store" /> store="task_search_store" />
</span> </span>
<span id="target_task" style="display: none"
tal:condition="view/followUpTask">&nbsp;
<label i18n:translate="move_to_task" for="input_task"
style="display: inline">to</label>
<span tal:content="view/followUpTask/title" />
<input type="hidden" name="task" id="input_task"
tal:attributes="value python:
view.getUidForObject(view.followUpTask)" />
</span>
</div> </div>
<div> <div>
<label i18n:translate="" for="start-end">Start - End</label> <div id="deadline"
<div id="start-end"> tal:condition="python:'deadline' in workItemType.fields">
<input type="text" name="start_date" style="width: 8em" <label i18n:translate="" for="deadline-input">Deadline</label>
dojoType="dijit.form.DateTextBox" <div id="deadline-input">
tal:attributes="value view/date" /> <input type="text" name="deadline" style="width: 8em"
<input type="text" name="start_time" style="width: 6em" dojoType="dijit.form.DateTextBox"
dojoType="dijit.form.TimeTextBox" tal:attributes="value view/deadline" /></div>
tal:attributes="value view/startTime" /> - </div>
<input type="text" name="end_time" style="width: 6em" <div id="start-end"
dojoType="dijit.form.TimeTextBox" tal:condition="python:'start-end' in workItemType.fields">
tal:attributes="value view/endTime" /></div> <label i18n:translate="" for="start-end-input">Start - End</label>
<label i18n:translate="" <div id="start-end-input">
for="duration-effort">Duration / Effort (hh:mm)</label> <input type="text" name="start_date" style="width: 8em"
<div id="duration-effort"> dojoType="dijit.form.DateTextBox"
<input type="text" name="duration" style="width: 5em" tal:attributes="value view/date" />
dojoType="dijit.form.ValidationTextBox" <input type="text" name="start_time" style="width: 6em"
regexp="-{0,1}[0-9]{1,2}(:[0-5][0-9]){0,1}" dojoType="dijit.form.TimeTextBox"
tal:attributes="value view/duration" /> / tal:attributes="value view/startTime" /> -
<input type="text" name="effort" style="width: 5em" <input type="text" name="end_time" style="width: 6em"
dojoType="dijit.form.ValidationTextBox" dojoType="dijit.form.TimeTextBox"
regexp="-{0,1}[0-9]{1,2}(:[0-5][0-9]){0,1}" tal:attributes="value view/endTime" /></div>
tal:attributes="value view/effort" /></div> </div>
<div id="duration-effort"
tal:condition="python:
'duration-effort' in workItemType.fields">
<label i18n:translate=""
for="duration-effort-input">Duration / Effort (hh:mm)</label>
<div id="duration-effort-input">
<input type="text" name="duration" style="width: 5em"
dojoType="dijit.form.ValidationTextBox"
regexp="-{0,1}[0-9]{1,2}(:[0-5][0-9]){0,1}"
tal:attributes="value view/duration" /> /
<input type="text" name="effort" style="width: 5em"
dojoType="dijit.form.ValidationTextBox"
regexp="-{0,1}[0-9]{1,2}(:[0-5][0-9]){0,1}"
tal:attributes="value view/effort" /></div>
</div>
</div> </div>
<div> <div>
<label i18n:translate="" for="comment">Comment</label> <label i18n:translate="" for="comment">Comment</label>
@ -187,6 +229,10 @@
<td><span i18n:translate="">Task</span>:</td> <td><span i18n:translate="">Task</span>:</td>
<td tal:content="item/object/title"></td> <td tal:content="item/object/title"></td>
</tr> </tr>
<tr>
<td><span i18n:translate="">Deadline</span>:</td>
<td tal:content="item/deadline"></td>
</tr>
<tr> <tr>
<td><span i18n:translate="">Start - End</span>:</td> <td><span i18n:translate="">Start - End</span>:</td>
<td><span tal:content="item/startDay" /> <td><span tal:content="item/startDay" />
@ -219,7 +265,8 @@
tal:attributes="href python:view.getUrlForTarget(party)" tal:attributes="href python:view.getUrlForTarget(party)"
tal:content="party/title" /></td> tal:content="party/title" /></td>
</tr> </tr>
<tr tal:condition="python:state.name in ('moved', 'moved_x')"> <tr tal:condition="python:state.name in ('moved', 'moved_x') and
item.targetWorkItem is not None">
<td><span i18n:translate="">Moved To</span>:</td> <td><span i18n:translate="">Moved To</span>:</td>
<td><a tal:define="task python:view.getObjectForUid(item.targetWorkItem.taskId)" <td><a tal:define="task python:view.getObjectForUid(item.targetWorkItem.taskId)"
tal:attributes="href python:view.getUrlForTarget(task)" tal:attributes="href python:view.getUrlForTarget(task)"