merge branch master
This commit is contained in:
commit
17012129b8
23 changed files with 565 additions and 171 deletions
|
@ -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):
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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({
|
dialog = new dijit.Dialog({
|
||||||
href: url
|
href: url
|
||||||
}, dojo.byId('dialog.' + dlgName));
|
}, dojo.byId('dialog.' + dlgName));
|
||||||
}
|
|
||||||
dialog.show();
|
dialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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:
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -1,9 +1,26 @@
|
||||||
<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="span-4">
|
||||||
|
<div tal:attributes="class python:
|
||||||
|
item.getCssClassForResource(related)"
|
||||||
|
tal:content="structure related/render" />
|
||||||
|
</div>
|
||||||
|
<div class="span-2 last" style="padding-top: 0.4em">
|
||||||
<div class="object-actions" style="padding-top: 0"
|
<div class="object-actions" style="padding-top: 0"
|
||||||
tal:define="url python:view.getUrlForTarget(related.context)"
|
tal:define="url python:view.getUrlForTarget(related.context)"
|
||||||
tal:condition="related/editable">
|
tal:condition="related/editable">
|
||||||
|
@ -24,9 +41,11 @@
|
||||||
<img tal:attributes="src
|
<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>
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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.
|
@ -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"
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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'',
|
||||||
|
|
|
@ -60,7 +60,6 @@ class AgendaItem(AdapterBase):
|
||||||
|
|
||||||
implements(IAgendaItem)
|
implements(IAgendaItem)
|
||||||
|
|
||||||
_adapterAttributes = AdapterBase._adapterAttributes
|
|
||||||
_contextAttributes = list(IAgendaItem)
|
_contextAttributes = list(IAgendaItem)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)))
|
||||||
|
|
|
@ -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 -->
|
||||||
|
|
|
@ -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;
|
||||||
|
showCheckboxes nothing;
|
||||||
|
showState nothing">
|
||||||
|
<div class ="WordSection1">
|
||||||
|
<div align="center">
|
||||||
|
<table class="MsoTableGrid" width="98%" cellpadding="0" cellspacing="0">
|
||||||
<metal:header use-macro="item/macros/header" />
|
<metal:header use-macro="item/macros/header" />
|
||||||
<metal:results use-macro="reportView/resultsRenderer" />
|
<metal:header use-macro="item/macros/rows" />
|
||||||
</div>
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</metal:doc>
|
||||||
|
|
||||||
|
|
||||||
<div metal:define-macro="header"
|
<metal:header define-macro="header"
|
||||||
tal:define="row results/first">
|
tal:define="row results/first">
|
||||||
<h1 i18n:translate="">Meeting Minutes</h1>
|
<tr style="background-color: #777777; color: white">
|
||||||
<h2 tal:define="col fields/eventTitle">
|
<td colspan="4">
|
||||||
<metal:col use-macro="python:item.getColumnRenderer(col)" /></h2>
|
<div tal:define="col fields/eventTitle"
|
||||||
<div>
|
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">
|
<span tal:define="col fields/eventStart">
|
||||||
<metal:col use-macro="python:item.getColumnRenderer(col)" /></span> -
|
<metal:col use-macro="python:item.getColumnRenderer(col)" /></span> -
|
||||||
<span tal:define="col fields/eventEnd">
|
<span tal:define="col fields/eventEnd">
|
||||||
<metal:col use-macro="python:item.getColumnRenderer(col)" /></span>
|
<metal:col use-macro="python:item.getColumnRenderer(col)" /></span>
|
||||||
</div>
|
</td>
|
||||||
<div tal:define="col fields/eventDescription">
|
</tr>
|
||||||
<metal:col use-macro="python:item.getColumnRenderer(col)" /></div>
|
<tr>
|
||||||
</div>
|
<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>
|
||||||
|
|
||||||
|
|
||||||
<div metal:define-macro="results">
|
<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
|
<input type="checkbox" checked
|
||||||
tal:attributes="onclick
|
tal:attributes="onclick
|
||||||
string:toggleCheckBoxes(this, '$cb_name:list')" /></th>
|
string:toggleCheckBoxes(this, '$cb_name:list')" /></th>
|
||||||
<th i18n:translate=""
|
<th colspan="4"
|
||||||
style="border: 1px solid grey">Task/Action</th>
|
i18n:translate=""
|
||||||
<th style="border: 1px solid grey"
|
style="border: 1px solid grey">Copy Agenda Items</th>
|
||||||
i18n:translate="">Who?</th>
|
<td tal:condition="showState"
|
||||||
<th style="border: 1px solid grey"
|
style="border: 1px solid #777777" />
|
||||||
i18n:translate="">When?</th>
|
|
||||||
<th style="border: 1px solid grey"
|
|
||||||
i18n:translate=""></th>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tal:task repeat="row results">
|
<tr>
|
||||||
<tr tal:repeat="colname python: ('title', 'description',)">
|
<td tal:condition="showCheckboxes" style="width: 2%"> </td>
|
||||||
|
<td style="width: 15%"> </td>
|
||||||
|
<td style="width: 53%"> </td>
|
||||||
|
<td style="width: 20%"> </td>
|
||||||
|
<td style="width: 12%"> </td>
|
||||||
|
<td tal:condition="showState" style="width: 2%"> </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"
|
<td tal:condition="showCheckboxes"
|
||||||
style="border: 1px solid grey">
|
style="border: 1px solid #777777" class="center">
|
||||||
<input type="checkbox" checked
|
<input type="checkbox" checked
|
||||||
tal:condition="python:colname == 'title'"
|
|
||||||
tal:attributes="name string:$cb_name:list;
|
tal:attributes="name string:$cb_name:list;
|
||||||
value row/context/uid" /></td>
|
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"
|
<td style="border: 1px solid grey"
|
||||||
tal:define="col report/fields/?colname"
|
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">
|
tal:attributes="class col/cssClass">
|
||||||
<metal:column use-macro="python:
|
<metal:column use-macro="python:
|
||||||
reportView.getColumnRenderer(col)" />
|
reportView.getColumnRenderer(col)" />
|
||||||
</td>
|
</td>
|
||||||
<td style="border: 1px solid grey" />
|
</tal:field>
|
||||||
<td style="border: 1px solid grey" />
|
<td tal:condition="showState"
|
||||||
<td style="border: 1px solid grey" />
|
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>
|
</tr>
|
||||||
<tal:workitems define="col report/fields/workItems">
|
|
||||||
<metal:column use-macro="python:
|
<metal:column use-macro="python:
|
||||||
reportView.getColumnRenderer(col)" />
|
reportView.getColumnRenderer(col)" />
|
||||||
</tal:workitems>
|
</tal:workitems>
|
||||||
</tal:task>
|
</tal:task>
|
||||||
|
</tal:tasks>
|
||||||
|
</metal:rows>
|
||||||
</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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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',)
|
||||||
|
|
|
@ -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">
|
<span id="target_task" style="display: none"
|
||||||
|
tal:condition="not:view/followUpTask">
|
||||||
<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,10 +139,29 @@
|
||||||
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">
|
||||||
|
<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">
|
||||||
|
<label i18n:translate="" for="deadline-input">Deadline</label>
|
||||||
|
<div id="deadline-input">
|
||||||
|
<input type="text" name="deadline" style="width: 8em"
|
||||||
|
dojoType="dijit.form.DateTextBox"
|
||||||
|
tal:attributes="value view/deadline" /></div>
|
||||||
|
</div>
|
||||||
|
<div id="start-end"
|
||||||
|
tal:condition="python:'start-end' in workItemType.fields">
|
||||||
|
<label i18n:translate="" for="start-end-input">Start - End</label>
|
||||||
|
<div id="start-end-input">
|
||||||
<input type="text" name="start_date" style="width: 8em"
|
<input type="text" name="start_date" style="width: 8em"
|
||||||
dojoType="dijit.form.DateTextBox"
|
dojoType="dijit.form.DateTextBox"
|
||||||
tal:attributes="value view/date" />
|
tal:attributes="value view/date" />
|
||||||
|
@ -134,9 +171,13 @@
|
||||||
<input type="text" name="end_time" style="width: 6em"
|
<input type="text" name="end_time" style="width: 6em"
|
||||||
dojoType="dijit.form.TimeTextBox"
|
dojoType="dijit.form.TimeTextBox"
|
||||||
tal:attributes="value view/endTime" /></div>
|
tal:attributes="value view/endTime" /></div>
|
||||||
|
</div>
|
||||||
|
<div id="duration-effort"
|
||||||
|
tal:condition="python:
|
||||||
|
'duration-effort' in workItemType.fields">
|
||||||
<label i18n:translate=""
|
<label i18n:translate=""
|
||||||
for="duration-effort">Duration / Effort (hh:mm)</label>
|
for="duration-effort-input">Duration / Effort (hh:mm)</label>
|
||||||
<div id="duration-effort">
|
<div id="duration-effort-input">
|
||||||
<input type="text" name="duration" style="width: 5em"
|
<input type="text" name="duration" style="width: 5em"
|
||||||
dojoType="dijit.form.ValidationTextBox"
|
dojoType="dijit.form.ValidationTextBox"
|
||||||
regexp="-{0,1}[0-9]{1,2}(:[0-5][0-9]){0,1}"
|
regexp="-{0,1}[0-9]{1,2}(:[0-5][0-9]){0,1}"
|
||||||
|
@ -146,6 +187,7 @@
|
||||||
regexp="-{0,1}[0-9]{1,2}(:[0-5][0-9]){0,1}"
|
regexp="-{0,1}[0-9]{1,2}(:[0-5][0-9]){0,1}"
|
||||||
tal:attributes="value view/effort" /></div>
|
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>
|
||||||
<div>
|
<div>
|
||||||
|
@ -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)"
|
||||||
|
|
Loading…
Add table
Reference in a new issue