merge branch master
This commit is contained in:
commit
153f0ee0e7
14 changed files with 558 additions and 11 deletions
|
@ -276,7 +276,8 @@ class ConceptView(BaseView):
|
||||||
if r.order != pos:
|
if r.order != pos:
|
||||||
r.order = pos
|
r.order = pos
|
||||||
|
|
||||||
def getChildren(self, topLevelOnly=True, sort=True, noDuplicates=True):
|
def getChildren(self, topLevelOnly=True, sort=True, noDuplicates=True,
|
||||||
|
useFilter=True):
|
||||||
form = self.request.form
|
form = self.request.form
|
||||||
#if form.get('loops.viewName') == 'index.html' and self.editable:
|
#if form.get('loops.viewName') == 'index.html' and self.editable:
|
||||||
if self.editable:
|
if self.editable:
|
||||||
|
@ -311,11 +312,13 @@ class ConceptView(BaseView):
|
||||||
break
|
break
|
||||||
if skip:
|
if skip:
|
||||||
continue
|
continue
|
||||||
options = IOptions(adapted(r.predicate), None)
|
if useFilter:
|
||||||
if options is not None and options('hide_children'):
|
options = IOptions(adapted(r.predicate), None)
|
||||||
continue
|
if options is not None and options('hide_children'):
|
||||||
if fv.check(r.context):
|
continue
|
||||||
yield r
|
if not fv.check(r.context):
|
||||||
|
continue
|
||||||
|
yield r
|
||||||
|
|
||||||
def checkCriteria(self, relation, criteria):
|
def checkCriteria(self, relation, criteria):
|
||||||
result = True
|
result = True
|
||||||
|
@ -347,9 +350,10 @@ class ConceptView(BaseView):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def isHidden(self, pr):
|
def isHidden(self, pr):
|
||||||
if (getName(pr.second.conceptType) in
|
predOptions = IOptions(adapted(pr.predicate))
|
||||||
IOptions(adapted(pr.predicate))('hide_parents_for', [])):
|
if predOptions('hide_parents'):
|
||||||
#IOptions(pr.predicate)('hide_parents_for', [])):
|
return True
|
||||||
|
if (getName(pr.second.conceptType) in predOptions('hide_parents_for', [])):
|
||||||
return True
|
return True
|
||||||
hideRoles = None
|
hideRoles = None
|
||||||
options = component.queryAdapter(adapted(pr.first), IOptions)
|
options = component.queryAdapter(adapted(pr.first), IOptions)
|
||||||
|
|
|
@ -23,7 +23,8 @@
|
||||||
</div>
|
</div>
|
||||||
<div metal:use-macro="views/relation_macros/clients" />
|
<div metal:use-macro="views/relation_macros/clients" />
|
||||||
|
|
||||||
<div tal:define="items view/children;
|
<div tal:define="items python:
|
||||||
|
view.getChildren(topLevelOnly=False, useFilter=False);
|
||||||
action string:remove;
|
action string:remove;
|
||||||
qualifier string:children;
|
qualifier string:children;
|
||||||
summary string:Currently assigned objects;
|
summary string:Currently assigned objects;
|
||||||
|
|
|
@ -159,11 +159,20 @@ class BasePart(Base):
|
||||||
gridPattern = []
|
gridPattern = []
|
||||||
showImage = True
|
showImage = True
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def childPredicates(self):
|
||||||
|
preds = [self.defaultPredicate]
|
||||||
|
for name in ['ispartof', 'hasoverview']:
|
||||||
|
pred = self.conceptManager.get(name)
|
||||||
|
if pred is not None:
|
||||||
|
preds.append(pred)
|
||||||
|
return preds
|
||||||
|
|
||||||
def getChildren(self):
|
def getChildren(self):
|
||||||
subtypeNames = (self.params.get('subtypes') or [''])[0].split(',')
|
subtypeNames = (self.params.get('subtypes') or [''])[0].split(',')
|
||||||
subtypes = [self.conceptManager[st] for st in subtypeNames if st]
|
subtypes = [self.conceptManager[st] for st in subtypeNames if st]
|
||||||
result = []
|
result = []
|
||||||
childRels = self.context.getChildRelations([self.defaultPredicate])
|
childRels = self.context.getChildRelations(self.childPredicates)
|
||||||
if subtypes:
|
if subtypes:
|
||||||
childRels = [r for r in childRels
|
childRels = [r for r in childRels
|
||||||
if r.second.conceptType in subtypes]
|
if r.second.conceptType in subtypes]
|
||||||
|
|
|
@ -219,6 +219,25 @@ Query Concepts and Query Views
|
||||||
>>> from loops.expert.browser.base import BaseQueryView
|
>>> from loops.expert.browser.base import BaseQueryView
|
||||||
|
|
||||||
|
|
||||||
|
Reports
|
||||||
|
=======
|
||||||
|
|
||||||
|
>>> from loops.expert.report import IReport, Report
|
||||||
|
>>> component.provideAdapter(Report, provides=IReport)
|
||||||
|
|
||||||
|
>>> report = Report(None)
|
||||||
|
|
||||||
|
>>> from loops.expert.report import IReportInstance, DefaultConceptReportInstance
|
||||||
|
>>> component.provideAdapter(DefaultConceptReportInstance,
|
||||||
|
... provides=IReportInstance,
|
||||||
|
... name='default_concept_report')
|
||||||
|
|
||||||
|
>>> from loops.expert.report import ReportTypeSourceList
|
||||||
|
>>> source = ReportTypeSourceList(report)
|
||||||
|
>>> list(source)
|
||||||
|
[(u'default_concept_report', u'Default Concept Report')]
|
||||||
|
|
||||||
|
|
||||||
Fin de partie
|
Fin de partie
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
|
|
@ -54,4 +54,25 @@
|
||||||
factory="loops.expert.browser.search.ActionExecutor"
|
factory="loops.expert.browser.search.ActionExecutor"
|
||||||
permission="zope.ManageContent" />
|
permission="zope.ManageContent" />
|
||||||
|
|
||||||
|
<!-- reporting -->
|
||||||
|
|
||||||
|
<zope:adapter
|
||||||
|
factory="loops.browser.common.SimpleTerms"
|
||||||
|
for="loops.expert.report.ReportTypeSourceList
|
||||||
|
zope.publisher.interfaces.browser.IBrowserRequest" />
|
||||||
|
|
||||||
|
<zope:adapter
|
||||||
|
name="report.html"
|
||||||
|
for="loops.interfaces.IConcept
|
||||||
|
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||||
|
provides="zope.interface.Interface"
|
||||||
|
factory="loops.expert.browser.report.ReportView"
|
||||||
|
permission="zope.View" />
|
||||||
|
|
||||||
|
<browser:page
|
||||||
|
name="results.html"
|
||||||
|
for="loops.interfaces.INode"
|
||||||
|
class="loops.expert.browser.report.ResultsView"
|
||||||
|
permission="zope.View" />
|
||||||
|
|
||||||
</configure>
|
</configure>
|
||||||
|
|
22
expert/browser/report.pt
Normal file
22
expert/browser/report.pt
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<html i18n:domain="loops">
|
||||||
|
|
||||||
|
|
||||||
|
<div metal:define-macro="main">
|
||||||
|
<div tal:attributes="class string:content-$level;">
|
||||||
|
<metal:block use-macro="view/concept_macros/concepttitle" />
|
||||||
|
<form method="post" name="report_data" action="results.html">
|
||||||
|
<tal:hidden define="params item/dynamicParams">
|
||||||
|
<input type="hidden"
|
||||||
|
tal:repeat="name params"
|
||||||
|
tal:attributes="name name;
|
||||||
|
value params/?name" /></tal:hidden>
|
||||||
|
<div metal:define-macro="buttons">
|
||||||
|
<input type="submit" name="report_execute" value="Execute Report"
|
||||||
|
i18n:attributes="value" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</html>
|
107
expert/browser/report.py
Normal file
107
expert/browser/report.py
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2011 Helmut Merz helmutm@cy55.de
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
View classes for reporting.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from urllib import urlencode
|
||||||
|
from zope import interface, component
|
||||||
|
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||||
|
from zope.cachedescriptors.property import Lazy
|
||||||
|
from zope.traversing.api import getName, getParent
|
||||||
|
|
||||||
|
from cybertools.browser.form import FormController
|
||||||
|
from loops.browser.concept import ConceptView
|
||||||
|
from loops.browser.node import NodeView
|
||||||
|
from loops.common import adapted, AdapterBase
|
||||||
|
from loops.expert.report import IReportInstance
|
||||||
|
from loops.organize.personal.browser.filter import FilterView
|
||||||
|
from loops.security.common import canWriteObject, checkPermission
|
||||||
|
from loops import util
|
||||||
|
from loops.util import _
|
||||||
|
|
||||||
|
|
||||||
|
report_template = ViewPageTemplateFile('report.pt')
|
||||||
|
results_template = ViewPageTemplateFile('results.pt')
|
||||||
|
|
||||||
|
|
||||||
|
class ReportView(ConceptView):
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def report_macros(self):
|
||||||
|
return self.controller.getTemplateMacros('report', report_template)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def macro(self):
|
||||||
|
return self.report_macros['main']
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def dynamicParams(self):
|
||||||
|
return self.request.form
|
||||||
|
|
||||||
|
|
||||||
|
class ResultsView(NodeView):
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def result_macros(self):
|
||||||
|
return self.controller.getTemplateMacros('results', results_template)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def macro(self):
|
||||||
|
return self.result_macros['main']
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def item(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def params(self):
|
||||||
|
params = dict(self.request.form)
|
||||||
|
if 'report_execute' in params:
|
||||||
|
del params['report_execute']
|
||||||
|
return params
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def report(self):
|
||||||
|
return adapted(self.virtualTargetObject)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def reportInstance(self):
|
||||||
|
instance = component.getAdapter(self.report, IReportInstance,
|
||||||
|
name=self.report.reportType)
|
||||||
|
instance.request = self.request
|
||||||
|
return instance
|
||||||
|
|
||||||
|
#@Lazy
|
||||||
|
def results(self):
|
||||||
|
return self.reportInstance.getResults(self.params)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def resultsRenderer(self):
|
||||||
|
return self.reportInstance.getResultsRenderer('results', self.result_macros)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def reportUrl(self):
|
||||||
|
url = self.virtualTargetUrl
|
||||||
|
return '?'.join((url, urlencode(self.params)))
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def displayedColumns(self):
|
||||||
|
return self.reportInstance.getActiveOutputFields()
|
||||||
|
|
22
expert/browser/results.pt
Normal file
22
expert/browser/results.pt
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<html i18n:domain="loops">
|
||||||
|
|
||||||
|
|
||||||
|
<div metal:define-macro="main"
|
||||||
|
tal:define="item nocall:item/virtualTarget;
|
||||||
|
report view/reportInstance">
|
||||||
|
<div tal:attributes="class string:content-$level;">
|
||||||
|
<metal:block use-macro="view/concept_macros/concepttitle" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a tal:attributes="href view/reportUrl">Back to the report definition</a>
|
||||||
|
</div>
|
||||||
|
<div metal:use-macro="view/resultsRenderer" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div metal:define-macro="results">
|
||||||
|
Default Results Listing
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</html>
|
|
@ -16,6 +16,35 @@
|
||||||
<adapter factory="loops.expert.setup.SetupManager"
|
<adapter factory="loops.expert.setup.SetupManager"
|
||||||
name="expert" />
|
name="expert" />
|
||||||
|
|
||||||
|
<!-- reporting -->
|
||||||
|
|
||||||
|
<adapter factory="loops.expert.report.Report"
|
||||||
|
provides="loops.expert.report.IReport" trusted="True" />
|
||||||
|
<class class="loops.expert.report.Report">
|
||||||
|
<require permission="zope.View"
|
||||||
|
interface="loops.expert.report.IReportSchema" />
|
||||||
|
<require permission="zope.ManageContent"
|
||||||
|
set_schema="loops.expert.report.IReportSchema" />
|
||||||
|
</class>
|
||||||
|
|
||||||
|
<adapter factory="loops.expert.report.DefaultConceptReportInstance"
|
||||||
|
name="default_concept_report"
|
||||||
|
provides="loops.expert.report.IReportInstance"
|
||||||
|
trusted="True" />
|
||||||
|
<class class="loops.expert.report.DefaultConceptReportInstance">
|
||||||
|
<require permission="zope.View"
|
||||||
|
interface="loops.expert.report.IReportInstance" />
|
||||||
|
<require permission="zope.ManageContent"
|
||||||
|
set_schema="loops.expert.report.IReportInstance" />
|
||||||
|
</class>
|
||||||
|
|
||||||
|
<utility
|
||||||
|
provides="zope.schema.interfaces.IVocabularyFactory"
|
||||||
|
component="loops.expert.report.ReportTypeSourceList"
|
||||||
|
name="loops.expert.reportTypeSource" />
|
||||||
|
|
||||||
|
<!-- includes -->
|
||||||
|
|
||||||
<include package=".browser" />
|
<include package=".browser" />
|
||||||
|
|
||||||
</configure>
|
</configure>
|
||||||
|
|
143
expert/report.py
Normal file
143
expert/report.py
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2011 Helmut Merz helmutm@cy55.de
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Report type, report concept adapter, and other reporting stuff.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from zope import schema, component
|
||||||
|
from zope.component import adapts
|
||||||
|
from zope.interface import Interface, Attribute, implements
|
||||||
|
from zope.cachedescriptors.property import Lazy
|
||||||
|
from zope.security.proxy import removeSecurityProxy
|
||||||
|
|
||||||
|
from cybertools.composer.report.base import Report as BaseReport
|
||||||
|
from cybertools.composer.report.base import LeafQueryCriteria, CompoundQueryCriteria
|
||||||
|
from cybertools.composer.report.interfaces import IReport as IBaseReport
|
||||||
|
from cybertools.composer.report.result import ResultSet, Row
|
||||||
|
from cybertools.util.jeep import Jeep
|
||||||
|
from loops.common import AdapterBase
|
||||||
|
from loops.interfaces import ILoopsAdapter
|
||||||
|
from loops.type import TypeInterfaceSourceList
|
||||||
|
from loops import util
|
||||||
|
from loops.util import _
|
||||||
|
|
||||||
|
|
||||||
|
# interfaces
|
||||||
|
|
||||||
|
class IReport(ILoopsAdapter):
|
||||||
|
""" The report adapter for the persistent object (concept) that stores
|
||||||
|
the report in the concept map.
|
||||||
|
"""
|
||||||
|
|
||||||
|
reportType = schema.Choice(
|
||||||
|
title=_(u'Report Type'),
|
||||||
|
description=_(u'The type of the report.'),
|
||||||
|
default=None,
|
||||||
|
source='loops.expert.reportTypeSource',
|
||||||
|
required=True)
|
||||||
|
|
||||||
|
|
||||||
|
class IReportSchema(IBaseReport, IReport):
|
||||||
|
""" All report attributes - use for security declarations.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class IReportInstance(Interface):
|
||||||
|
""" The report-type-specific object (an adapter on the report) that
|
||||||
|
does the real report execution stuff.
|
||||||
|
"""
|
||||||
|
|
||||||
|
label = Attribute('The user-friendly label of the report type specified '
|
||||||
|
'by this instance class.')
|
||||||
|
|
||||||
|
|
||||||
|
# report concept adapter and instances
|
||||||
|
|
||||||
|
class Report(AdapterBase):
|
||||||
|
|
||||||
|
implements(IReport)
|
||||||
|
|
||||||
|
_contextAttributes = list(IReport)
|
||||||
|
|
||||||
|
TypeInterfaceSourceList.typeInterfaces += (IReport,)
|
||||||
|
|
||||||
|
|
||||||
|
class ReportInstance(BaseReport):
|
||||||
|
|
||||||
|
implements(IReportInstance)
|
||||||
|
adapts(IReport)
|
||||||
|
|
||||||
|
rowFactory = Row
|
||||||
|
|
||||||
|
def __init__(self, context):
|
||||||
|
self.context = context
|
||||||
|
|
||||||
|
def getResultsRenderer(self, name, macros):
|
||||||
|
return macros[name]
|
||||||
|
|
||||||
|
def getResults(self, dynaParams=None):
|
||||||
|
crit = self.queryCriteria
|
||||||
|
if crit is None:
|
||||||
|
return []
|
||||||
|
for k, v in dynaParams.items():
|
||||||
|
if k in crit.parts.keys():
|
||||||
|
crit.parts[k].value = v
|
||||||
|
parts = Jeep(crit.parts)
|
||||||
|
result = list(self.selectObjects(parts)) # may modify parts
|
||||||
|
qc = CompoundQueryCriteria(parts)
|
||||||
|
return ResultSet(self, result, rowFactory=self.rowFactory,
|
||||||
|
sortCriteria=self.getSortCriteria(), queryCriteria=qc)
|
||||||
|
|
||||||
|
def selectObjects(self, parts):
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class ReportTypeSourceList(object):
|
||||||
|
|
||||||
|
implements(schema.interfaces.IIterableSource)
|
||||||
|
|
||||||
|
def __init__(self, context):
|
||||||
|
self.context = context
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return iter(self.reportTypes)
|
||||||
|
|
||||||
|
def __contains__(self, value):
|
||||||
|
return value in [item[0] for item in self]
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def reportTypes(self):
|
||||||
|
result = []
|
||||||
|
for item in component.getAdapters([self.context], IReportInstance):
|
||||||
|
name, adapter = item
|
||||||
|
adapter = removeSecurityProxy(adapter)
|
||||||
|
label = getattr(adapter, 'label', name)
|
||||||
|
result.append((name, label,))
|
||||||
|
return result
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.reportTypes)
|
||||||
|
|
||||||
|
|
||||||
|
# default concept report
|
||||||
|
|
||||||
|
class DefaultConceptReportInstance(ReportInstance):
|
||||||
|
|
||||||
|
label = u'Default Concept Report'
|
||||||
|
|
|
@ -180,6 +180,16 @@ So we use the PersonWorkItems view, assigning john to the query.
|
||||||
'creator': '33'}>]
|
'creator': '33'}>]
|
||||||
|
|
||||||
|
|
||||||
|
Work Reports
|
||||||
|
============
|
||||||
|
|
||||||
|
>>> from loops.organize.work.report import WorkReportInstance
|
||||||
|
>>> from loops.expert.report import IReportInstance
|
||||||
|
>>> component.provideAdapter(WorkReportInstance,
|
||||||
|
... provides=IReportInstance,
|
||||||
|
... name='work_report')
|
||||||
|
|
||||||
|
|
||||||
Fin de partie
|
Fin de partie
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,19 @@
|
||||||
class="loops.organize.work.browser.WorkItemInfo"
|
class="loops.organize.work.browser.WorkItemInfo"
|
||||||
permission="zope.View" />
|
permission="zope.View" />
|
||||||
|
|
||||||
|
<!-- reporting -->
|
||||||
|
|
||||||
|
<zope:adapter factory="loops.organize.work.report.WorkReportInstance"
|
||||||
|
name="work_report"
|
||||||
|
provides="loops.expert.report.IReportInstance"
|
||||||
|
trusted="True" />
|
||||||
|
<zope:class class="loops.organize.work.report.WorkReportInstance">
|
||||||
|
<require permission="zope.View"
|
||||||
|
interface="loops.expert.report.IReportInstance" />
|
||||||
|
<require permission="zope.ManageContent"
|
||||||
|
set_schema="loops.expert.report.IReportInstance" />
|
||||||
|
</zope:class>
|
||||||
|
|
||||||
<!-- setup -->
|
<!-- setup -->
|
||||||
|
|
||||||
<zope:adapter factory="loops.organize.work.setup.SetupManager"
|
<zope:adapter factory="loops.organize.work.setup.SetupManager"
|
||||||
|
|
86
organize/work/report.py
Normal file
86
organize/work/report.py
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2011 Helmut Merz helmutm@cy55.de
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Work report definitions.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||||
|
from zope.cachedescriptors.property import Lazy
|
||||||
|
from zope.component import adapter
|
||||||
|
|
||||||
|
from cybertools.composer.report.base import Report
|
||||||
|
from cybertools.composer.report.base import LeafQueryCriteria, CompoundQueryCriteria
|
||||||
|
from cybertools.composer.report.field import Field
|
||||||
|
from cybertools.composer.report.result import ResultSet, Row as BaseRow
|
||||||
|
from cybertools.util.jeep import Jeep
|
||||||
|
from loops.expert.report import ReportInstance
|
||||||
|
|
||||||
|
results_template = ViewPageTemplateFile('results.pt')
|
||||||
|
|
||||||
|
|
||||||
|
task = Field('task', u'Task',
|
||||||
|
description=u'The task to which work items belong.',
|
||||||
|
executionSteps=['query', 'output', 'sort'])
|
||||||
|
work = Field('work', u'Work',
|
||||||
|
description=u'The short description of the work.',
|
||||||
|
executionSteps=['output'])
|
||||||
|
workDescription = Field('workDescription', u'Work Description',
|
||||||
|
description=u'The long description of the work.',
|
||||||
|
executionSteps=['output'])
|
||||||
|
day = Field('day', u'Day',
|
||||||
|
description=u'The day the work was done.',
|
||||||
|
executionSteps=['output', 'sort'])
|
||||||
|
dayFrom = Field('dayFrom', u'Start Day',
|
||||||
|
description=u'The first day from which to select work.',
|
||||||
|
executionSteps=['query'])
|
||||||
|
dayTo = Field('dayTo', u'End Day',
|
||||||
|
description=u'The last day until which to select work.',
|
||||||
|
executionSteps=['query'])
|
||||||
|
|
||||||
|
|
||||||
|
class WorkRow(BaseRow):
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class WorkReportInstance(ReportInstance):
|
||||||
|
|
||||||
|
type = "deliverables"
|
||||||
|
label = u'Work Report'
|
||||||
|
|
||||||
|
rowFactory = WorkRow
|
||||||
|
fields = Jeep((day, dayFrom, dayTo, task, work, workDescription))
|
||||||
|
defaultOutputFields = fields
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def queryCriteria(self):
|
||||||
|
# TODO: take from persistent report where appropriate
|
||||||
|
crit = [LeafQueryCriteria(f.name, f.operator, None, f)
|
||||||
|
for f in self.getAllQueryFields()]
|
||||||
|
return CompoundQueryCriteria(crit)
|
||||||
|
|
||||||
|
def getResultsRenderer(self, name, defaultMacros):
|
||||||
|
return results_template.macros[name]
|
||||||
|
|
||||||
|
def selectObjects(self, parts):
|
||||||
|
task = parts.get('task')
|
||||||
|
if not task:
|
||||||
|
return []
|
||||||
|
return []
|
||||||
|
|
61
organize/work/results.pt
Normal file
61
organize/work/results.pt
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
<html i18n:domain="loops">
|
||||||
|
|
||||||
|
|
||||||
|
<div metal:define-macro="results">
|
||||||
|
<h2 i18n:translate="">Work Items</h2>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th tal:repeat="col view/displayedColumns"
|
||||||
|
tal:content="col/title"
|
||||||
|
i18n:translate="" />
|
||||||
|
</tr>
|
||||||
|
<tr tal:repeat="row view/results">
|
||||||
|
<tal:column repeat="col view/displayedColumns">
|
||||||
|
<metal:column use-macro="python: view.getColumnRenderer(col.renderer)" />
|
||||||
|
</tal:column>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div metal:define-macro="xx_results">
|
||||||
|
Work Items Listing
|
||||||
|
<table class="listing">
|
||||||
|
<tr>
|
||||||
|
<tal:colheader repeat="column work/allColumns">
|
||||||
|
<th tal:condition="python: column in work.columns"
|
||||||
|
tal:content="column"
|
||||||
|
i18n:translate="">Task</th>
|
||||||
|
</tal:colheader>
|
||||||
|
</tr>
|
||||||
|
<tal:workitem tal:repeat="row work/listWorkItems">
|
||||||
|
<tr tal:condition="row/monthChanged">
|
||||||
|
<td class="headline"
|
||||||
|
tal:attributes="colspan python: len(work.columns)"
|
||||||
|
tal:content="row/month">2009-01</td></tr>
|
||||||
|
<tr tal:attributes="class python:
|
||||||
|
(repeat['row'].odd() and 'even' or 'odd')">
|
||||||
|
<td class="nowrap center"
|
||||||
|
tal:define="today python: row.isToday and ' today' or ''"
|
||||||
|
tal:attributes="title row/weekDay;
|
||||||
|
class string:nowrap center$today"
|
||||||
|
i18n:attributes="title"
|
||||||
|
tal:content="row/day">2007-03-30</td>
|
||||||
|
<td class="nowrap center" tal:content="row/start">17:30</td>
|
||||||
|
<td class="nowrap center" tal:content="row/end">20:00</td>
|
||||||
|
<td class="nowrap center" tal:content="row/duration">2:30</td>
|
||||||
|
<td tal:condition="python: 'Task' in work.columns">
|
||||||
|
<a tal:attributes="href row/objectData/url"
|
||||||
|
tal:content="row/objectData/title">Task</a></td>
|
||||||
|
<td tal:condition="python: 'User' in work.columns">
|
||||||
|
<a tal:attributes="href row/user/url"
|
||||||
|
tal:content="row/user/title">John</a></td>
|
||||||
|
<td tal:content="row/track/title"
|
||||||
|
tal:attributes="title row/descriptionPlain">Title</td>
|
||||||
|
</tr>
|
||||||
|
</tal:workitem>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</html>
|
Loading…
Add table
Reference in a new issue