[Zope3-checkins] CVS: zopeproducts/bugtracker/browser - bug_listing_compressed.pt:1.1 bug_listing_normal.pt:1.1 bug.py:1.11 bug_overview.pt:1.5 configure.zcml:1.9 dependencies.pt:1.4 tracker.py:1.12 tracker_overview.pt:1.8

Stephan Richter srichter at cosmos.phy.tufts.edu
Thu Aug 28 02:23:02 EDT 2003


Update of /cvs-repository/zopeproducts/bugtracker/browser
In directory cvs.zope.org:/tmp/cvs-serv11184/browser

Modified Files:
	bug.py bug_overview.pt configure.zcml dependencies.pt 
	tracker.py tracker_overview.pt 
Added Files:
	bug_listing_compressed.pt bug_listing_normal.pt 
Log Message:
Major usibility improvements landed:

- You can now filter also by the owner. This is good when you want to 
  see all the bugs you are responsible for for example.

- There is a "View Type" in the tracker overview, which specifes how the
  found bugs are displayed. "normal" is what we had till now and 
  "compressed" displays the bugs in a table (one bug per line). This 
  feature was requested by Fred Drake, who liked this particular feature
  in the SF bug tracker.

- You can now collapse the filter options, so that more bugs fit on your 
  screen.

- When seeing the bug overview, you now have an "Add Bug" link there, which
  enables you to add a new bug that is a dependency of the currently viewed 
  one. This feature will increase input speed by multiples. Thanks goes to
  Jim for suggesting this.

- In the bug dependency screen you can also collapse the edit interface.

- The dependency edit interface is not shown as part of the "Dependencies" 
  screen, if the user has not the necessary rights to modify this data.

- The management widget for dependencies has been switched to a different
  model which is more scalable and user savy. Furthermore, you cannot just 
  set Dependencies (children) but also Dependents (Parents), which makes it
  much easier to manage dependencies in general, since you often want to 
  specify the Dependent and not the Dependency. Thanks to Jim again for 
  suggesting this.

- Chnaged the dependency annotation key to be a valid file, so that it 
  plays nice with fssync. This means, if you have an existing bug tracker 
  you cannot just upgrade your software, since you would loose all of your 
  dependencies. The easy solution is to export the entire bug tracker to 
  XML first, before upgrading, so that you can easily import it after the 
  upgrade again.

** WARNING: THIS CHECKIN BREAKS BACKWARD COMPATIBILITY! SEE LAST NOTE ABOVE**


=== Added File zopeproducts/bugtracker/browser/bug_listing_compressed.pt ===
<table class="listing" width="100%" 
       style="font-size:80%;">
  <tr>
    <th width="70%">Title (ID)</th>
    <th width="10%">Submitter</th>
    <th width="10%">Date/Time</th>
    <th width="10%">Owners</th>
  </tr>
  <tal:block repeat="bug view/getBugs" i18n:domain="bugtracker">
    <tr class=""
        tal:define="oddrow repeat/bug/odd"
        tal:attributes="class python:oddrow and 'even' or 'odd'">

      <td>
        <a class="" href="" 
            tal:attributes="
              href string:./${bug/name};
              class string:node ${bug/context/status} ${bug/context/priority}">
          <span tal:replace="bug/context/title" />
          (<span tal:replace="bug/name" />)
        </a>
      </td>
      <td tal:content="bug/submitter/getLogin" />
      <td tal:content="bug/shortCreated" />
      <td tal:content="bug/owners" />
    </tr>
  </tal:block>
</table>

=== Added File zopeproducts/bugtracker/browser/bug_listing_normal.pt ===
  <tal:block repeat="bug view/getBugs" i18n:domain="bugtracker">
    <div class=""
        tal:define="oddrow repeat/bug/odd"
        tal:attributes="class python:oddrow and 'even' or 'odd'">
      <h5 class="summary_title" >
        <a href="" 
            tal:attributes="href string:./${bug/name}/@@overview.html"
            i18n:translate="">
          Bug #<d tal:replace="bug/name" i18n:name="bug_id">1</d> - 
          <d tal:replace="bug/context/title" i18n:name="bug_title">
            Bug Title
          </d> 
        </a>
      </h5>

      <div class="summary_content">
        <div class="summary_condition">
          <span i18n:translate="">Status:</span> 
            <span tal:attributes="class bug/context/status" 
                  tal:content="bug/status/title">New</span> - 
          <span i18n:translate="">Priority:</span> 
            <span tal:attributes="class bug/context/priority"
                  tal:content="bug/priority/title">Normal</span> - 
          <span i18n:translate="">Type: </span>
            <b tal:replace="bug/type/title">Bug</b>
        </div>

        <div class="summary_body" tal:content="bug/descriptionPreview">
          Message Description Sneak Preview goes here...
        </div>

        <div class="summary_metadata" i18n:translate="">
          Posted by <b tal:content="bug/submitter/getTitle" 
                       i18n:name="submitter">Submitter</b> 
          on <b tal:replace="bug/created" 
                i18n:name="created_date">2003/01/01</b>
          - <b tal:replace="bug/numberOfComments" 
               i18n:name="num_comments">3</b> comments
        </div>
      </div>
    </div>
  </tal:block>


=== zopeproducts/bugtracker/browser/bug.py 1.10 => 1.11 ===
--- zopeproducts/bugtracker/browser/bug.py:1.10	Tue Aug 12 23:41:48 2003
+++ zopeproducts/bugtracker/browser/bug.py	Thu Aug 28 01:22:31 2003
@@ -15,13 +15,10 @@
 
 $Id$
 """
+import docutils
 import re
 
-from zope.component import getService, getAdapter
-from zope.component.interfaces import IViewFactory
-from zope.interface import implements
-from zope.proxy import removeAllProxies
-from zope.schema.vocabulary import getVocabularyRegistry
+from zope.app import zapi
 from zope.app.browser.form.vocabularywidget import VocabularyEditWidget
 from zope.app.browser.form.widget import TextWidget, TextAreaWidget
 from zope.app.context import ContextWrapper
@@ -29,12 +26,17 @@
 from zope.app.security.grants.principalrole import principalRoleManager
 from zope.app.security.settings import Allow
 from zope.app.services.servicenames import Authentication
-from zope.app.traversing import getParent, getName
 from zope.app.interfaces.dublincore import IZopeDublinCore
 from zope.app.interfaces.size import ISized
 from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
 from zope.app.browser.form.widget import MultiListWidget, ListWidget
 from zope.app.browser.container.adding import Adding
+from zope.component.interfaces import IViewFactory
+from zope.exceptions import Unauthorized, ForbiddenAttribute
+from zope.interface import implements
+from zope.proxy import removeAllProxies
+from zope.schema.vocabulary import getVocabularyRegistry
+from zope.security.checker import getChecker, ProxyFactory
 
 from zopeproducts.bugtracker.interfaces import IComment
 from zopeproducts.bugtracker.interfaces import IBugDependencies
@@ -71,52 +73,86 @@
     """Get's all the fancy expressions for the attribute values."""
 
     def created(self):
-        dc = getAdapter(self.context, IZopeDublinCore)
+        dc = zapi.getAdapter(self.context, IZopeDublinCore)
         formatter = self.request.locale.getDateTimeFormatter('short')
         return formatter.format(dc.created)
 
     def modified(self):
-        dc = getAdapter(self.context, IZopeDublinCore)
+        dc = zapi.getAdapter(self.context, IZopeDublinCore)
         formatter = self.request.locale.getDateTimeFormatter('short')
         if dc.modified is None:
             return self.created()
         return formatter.format(dc.modified)
 
     def submitter(self):
-        auth = getService(self.context, Authentication)
+        auth = zapi.getService(self.context, Authentication)
         return auth.getPrincipal(self.context.submitter)
 
     def description(self):
-        html = HTML(self.context.description, level=3)
+        # format with strings
+        pub = docutils.core.Publisher()
+        pub.set_reader('standalone', None, 'restructuredtext')
+        pub.set_writer('html')
+
+        # go with the defaults
+        pub.get_settings()
+
+        # this is needed, but doesn't seem to do anything
+        pub.settings._destination = ''
+
+        # use the Zope 3 stylesheet
+        pub.settings.stylesheet = 'zope3.css'
+
+        # set the reporting level to something sane (1 being the smallest)
+        pub.settings.report_level = 1
+
+        # don't break if we get errors
+        pub.settings.halt_level = 6
+
+        # input
+        pub.source = docutils.io.StringInput(source=self.context.description)
+
+        # output - not that it's needed
+        pub.destination = docutils.io.StringOutput(encoding='UTF-8')
+
+        # parse!
+        document = pub.reader.read(pub.source, pub.parser, pub.settings)
+
+        # transform
+        pub.apply_transforms(document)
+
+        # do the format
+        html = pub.writer.write(document, pub.destination)
         html = re.sub(
-            r'(?sm)^<html.*<body.*?>\n(.*)</body>\n</html>\n',r'\1', html)
+            r'(?sm)^<\?xml.*<html.*<body.*?>\n(.*)</body>\n</html>\n',r'\1',
+            html)
         return html
 
     def status(self):
         registry = getVocabularyRegistry()
-        types = registry.get(getParent(self.context), 'Stati')
+        types = registry.get(zapi.getParent(self.context), 'Stati')
         return types.getTerm(self.context.status)
 
     def type(self):        
         registry = getVocabularyRegistry()
-        types = registry.get(getParent(self.context), 'BugTypes')
+        types = registry.get(zapi.getParent(self.context), 'BugTypes')
         return types.getTerm(self.context.type)
 
     def release(self):
         if self.context.release is None:
             return u'not specified'
         registry = getVocabularyRegistry()
-        types = registry.get(getParent(self.context), 'Releases')
+        types = registry.get(zapi.getParent(self.context), 'Releases')
         return types.getTerm(self.context.release)
 
     def priority(self):
         registry = getVocabularyRegistry()
-        types = registry.get(getParent(self.context), 'Priorities')
+        types = registry.get(zapi.getParent(self.context), 'Priorities')
         return types.getTerm(self.context.priority)
 
     def owners(self):
         registry = getVocabularyRegistry()
-        users = registry.get(getParent(self.context), 'Users')
+        users = registry.get(zapi.getParent(self.context), 'Users')
         return map(lambda owner: users.getTerm(owner), self.context.owners)
 
 
@@ -159,6 +195,23 @@
         return '../'+self.context.contentName
 
 
+class AddDependentBug(BugForm):
+
+    def __init__(self, context, request):
+        super(AddDependentBug, self).__init__(context, request)
+        self.label = "Add Bug (Dependent: %s)" %context.title
+
+    def add(self, content):
+        container = zapi.getParent(self.context)
+        name = container.setObject('auto', content)
+        deps = zapi.getAdapter(self.context, IBugDependencies)
+        deps.dependencies += (name,)
+        return container[name]
+
+    def nextURL(self):
+        return './overview.html'
+
+
 class EditBug(BugBaseView, BugForm):
 
     def update(self):
@@ -185,34 +238,65 @@
         attchs = []
         for name, obj in self.context.items():
             if not IComment.isImplementedBy(obj):
-                size = getAdapter(obj, ISized)
+                size = zapi.getAdapter(obj, ISized)
                 attchs.append({'name': name, 'size': size.sizeForDisplay()})
         return attchs
         
     def dependencies(self):
-        deps = getAdapter(self.context, IBugDependencies)
+        deps = zapi.getAdapter(self.context, IBugDependencies)
         return deps.dependencies
 
 
 class Dependencies(object):
 
-    def dependencies(self):
-        deps = getAdapter(self.context, IBugDependencies)
-        return deps.dependencies
+    def __init__(self, context, request):
+        super(Dependencies, self).__init__(context, request)
+        # For efficiency get these values once and be done.
+        deps = zapi.getAdapter(self.context, IBugDependencies)
+        # If the two conditions are not fulfilled, we are not going to need
+        # the values.
+        if self.canChangeDependencies() and self.getShowDepsOptions():
+            self.dependencies = deps.dependencies
+            self.dependents = deps.dependents    
+
+    def dependencyValues(self):
+        deps = zapi.getAdapter(self.context, IBugDependencies)
+        dep_type = self.request.get('dep_type', 'dependencies')
+        if dep_type == 'dependencies':
+            return self.dependencies
+        else:
+            return self.dependents            
 
     def availableBugs(self):
-        tracker = getParent(self.context)
+        tracker = zapi.getParent(self.context)
         bugs = []
         for name, bug in tracker.items():
             # Make sure we do not list the bug itself
-            if name != getName(self.context):
+            if name != zapi.name(self.context):
                 bugs.append({'name': name, 'title': bug.title})
         return bugs
 
-    def setDependencies(self, dependencies=()):
-        deps = getAdapter(self.context, IBugDependencies)
-        deps.setDependencies(dependencies)
-        return self.request.response.redirect('./@@dependencies.html')
+    def setDependencyValues(self):
+        dep_type = self.request.get('dep_type', 'dependencies')
+        deps = zapi.getAdapter(self.context, IBugDependencies)
+
+        if 'ADD' in self.request and 'add_deps' in self.request:
+            if dep_type == 'dependencies':
+                deps.addDependencies(tuple(self.request['add_deps']))
+            else:
+                deps.addDependents(tuple(self.request['add_deps']))
+
+        if 'DELETE' in self.request and 'del_deps' in self.request:
+            if dep_type == 'dependencies':
+                deps.deleteDependencies(tuple(self.request['del_deps']))
+            else:
+                deps.deleteDependents(tuple(self.request['del_deps']))
+
+        self.setShowDepsOptions()
+        self.setDepType()
+
+        return self.request.response.redirect(
+            './@@dependencies.html?dep_type=' + dep_type)
 
     def _branchHTML(self, children):
         html = '<ul>\n'
@@ -224,7 +308,7 @@
         return html
 
     def branch(self):
-        deps = getAdapter(self.context, IBugDependencies)
+        deps = zapi.getAdapter(self.context, IBugDependencies)
         children = deps.findChildren()
         return self._branchHTML(children)
 
@@ -235,7 +319,7 @@
         return all
 
     def getStatistics(self):
-        deps = getAdapter(self.context, IBugDependencies)
+        deps = zapi.getAdapter(self.context, IBugDependencies)
         children = deps.findChildren()
         all = self._getAllSubs(children)
         all_num = len(all)
@@ -254,13 +338,31 @@
                  }
         return stats
 
+    def getDepType(self):
+        return self.request.cookies.get('dep_type', 'dependencies')
+
+    def setDepType(self):
+        value = self.request.get('dep_type', 'dependencies')
+        self.request.response.setCookie('dep_type', value)
+
+    def getShowDepsOptions(self):
+        return int(self.request.cookies.get('show_deps_options', '1'))
+
+    def setShowDepsOptions(self):
+        if 'COLLAPSE' in self.request:
+            value = '0'
+        else:
+            value = '1'
+        self.request.response.setCookie('show_deps_options', value)
+
     def canChangeDependencies(self):
-        pid = self.request.user.getId()
-        # 100% buggy!
-        roles = principalRoleManager.getRolesForPrincipal(pid)
-        roles = filter(lambda r: r[1] == Allow, roles)
-        roles = map(lambda r: r[0], roles)
-        #return 'bugtracker.Editor' in roles
+        deps = zapi.getAdapter(self.context, IBugDependencies)
+        proxy = ProxyFactory(deps)
+        checker = getChecker(proxy)
+        try:
+            checker.check_setattr(self, 'dependencies')
+        except (Unauthorized, ForbiddenAttribute):
+            return False
         return True
     
     legend = ViewPageTemplateFile('legend.pt')
@@ -273,7 +375,7 @@
         self.request = request
 
     def name(self):
-        return getName(self.context)
+        return zapi.name(self.context)
 
     __call__ = ViewPageTemplateFile('branchentry.pt')
     


=== zopeproducts/bugtracker/browser/bug_overview.pt 1.4 => 1.5 ===
--- zopeproducts/bugtracker/browser/bug_overview.pt:1.4	Tue Aug 12 18:50:57 2003
+++ zopeproducts/bugtracker/browser/bug_overview.pt	Thu Aug 28 01:22:31 2003
@@ -69,6 +69,9 @@
   
     </tal:block>
   </div>
+  <div class="action" i18n:domain="bugtracker">
+    <a href="./@@AddBug" i18n:translate="">Add Bug</a>
+  </div>
   
   <h4 i18n:translate="" i18n:domain="bugtracker">Attachments</h4>
   <ul id="attachments" tal:condition="view/attachments">


=== zopeproducts/bugtracker/browser/configure.zcml 1.8 => 1.9 ===
--- zopeproducts/bugtracker/browser/configure.zcml:1.8	Tue Aug 12 14:55:11 2003
+++ zopeproducts/bugtracker/browser/configure.zcml	Thu Aug 28 01:22:31 2003
@@ -127,6 +127,19 @@
       class=".bug.AddBug"
       menu="add_bugtracker" title="Bug"/>
 
+  <!-- Add Dependent Bug -->
+  <addform
+      label="Add Dependent Bug"
+      name="AddBug"
+      for="zopeproducts.bugtracker.interfaces.IBug"
+      schema="zopeproducts.bugtracker.interfaces.IBug"
+      content_factory="zopeproducts.bugtracker.bug.Bug"
+      permission="bugtracker.AddBug"
+      fields="title description type owners status priority release"
+      template="bug_add.pt"
+      class=".bug.AddDependentBug"
+      menu="add_bugtracker" title="Bug"/>
+
   <editform
       schema="zopeproducts.bugtracker.interfaces.IBug"
       for="zopeproducts.bugtracker.interfaces.IBug"
@@ -152,7 +165,7 @@
       permission="bugtracker.ViewBug">
       <page name="dependencies.html" template="dependencies.pt"
             menu="zmi_views" title="Dependencies" />
-      <page name="setDependencies.html" attribute="setDependencies" />
+      <page name="setDependencies.html" attribute="setDependencyValues" />
   </pages>
 
   <pages


=== zopeproducts/bugtracker/browser/dependencies.pt 1.3 => 1.4 ===
--- zopeproducts/bugtracker/browser/dependencies.pt:1.3	Tue Aug 12 14:55:11 2003
+++ zopeproducts/bugtracker/browser/dependencies.pt	Thu Aug 28 01:22:31 2003
@@ -9,49 +9,99 @@
 </head>
 
 <body i18n:domain="bugtracker">
-<div metal:fill-slot="body">
+<div metal:fill-slot="body"
+     tal:define="dep_type python:view.request.get('dep_type', 'dependencies')">
 
-  <form action="setDependencies.html" method="post"
-      tal:condition="view/canChangeDependencies">
-
-    <div id="explanation" i18n:translate="">
-       In the selection box below you can select the bugs that have to be
-       completed <em>before</em> this bug can be completed.
-    </div>
+  <div class="box"
+    tal:condition="view/canChangeDependencies">
+    <h4 style="padding: 0.3em;">Set Dependencies/Dependents</h4>
+    <div class="body"><div class="even">
+      <div id="explanation"
+           tal:condition="view/getShowDepsOptions">
+        Depending on which view you selected, you look at the dependencies
+        differently, once you look at the parents and once at the children of a
+        bug in the dependency tree:
+        <ul>
+          <li i18n:translate="">Dependencies - Bugs that have to be completed 
+            before this bug can be closed.</li>
+          <li i18n:translate="">Dependents - This bug has to be completed in
+            before the Dependents can be closed.</li>
+        </ul>
+      </div>
+    
+      <form action="setDependencies.html" method="post">
+    
+        <div
+          tal:condition="view/getShowDepsOptions">
 
-    <div>
-      <div class="row">
-        <div class="label" i18n:translate="">Dependencies</div>
-        <div class="field">
-          <select name="dependencies:list" size="5" multiple="">
-              <div tal:repeat="bug view/availableBugs" tal:omit-tag="">
-              <b tal:content="bug/name" />
-              <b tal:content="bug/title" />
-            <option 
-                value="" selected=""
-                tal:content="string: ${bug/title} (${bug/name})"
-                tal:attributes="value bug/name"
-                tal:condition="python: bug['name'] in view.dependencies()">
-              Bug1
-            </option>
-            <option 
-               tal:content="string: ${bug/title} (${bug/name})"
-               tal:attributes="value bug/name"
-               tal:condition="
-                   python: bug['name'] not in view.dependencies()">
-              Bug1
-            </option>
+          <div class="row">
+            <div class="field">
+              <table width="100%"><tr><td width="48%">
+              <b i18n:translate="">Available Bugs</b><br/>
+              <select name="add_deps:list" size="5" multiple=""
+                  style="width: 100%">
+                <div tal:repeat="bug view/availableBugs" tal:omit-tag="">
+                  <option 
+                      value=""
+                      tal:content="string: ${bug/title} (${bug/name})"
+                      tal:attributes="value bug/name"
+                      tal:condition="
+                          python: bug['name'] not in view.dependencyValues()">
+                    Bug1
+                  </option>
+                </div> 
+              </select>
+              </td><td width="4%">
+                <input type="submit" name="ADD" value="-->" /><br/>
+                <input type="submit" name="DELETE" value="<--" />
+              </td><td width="48%">
+              <div tal:condition="python:dep_type == 'dependencies'">
+                <b i18n:translate="">Dependencies</b>
+                [<a href="@@setDependencies.html?dep_type=dependents" 
+                    i18n:translate="">Dependents</a>]
+              </div>
+              <div tal:condition="python:dep_type == 'dependents'">
+                <b i18n:translate="">Dependents</b>
+                [<a href="@@setDependencies.html?dep_type=dependencies" 
+                    i18n:translate="">Dependencies</a>]
+              </div>
+              <input type="hidden" name="dep_type" value=""
+                  tal:attributes="value dep_type"> 
+    
+              <br/>
+              <select name="del_deps:list" size="5" multiple=""
+                  style="width: 100%">
+                <div tal:repeat="bug view/availableBugs" tal:omit-tag="">
+                  <option 
+                     tal:content="string: ${bug/title} (${bug/name})"
+                     tal:attributes="value bug/name"
+                     tal:condition="
+                         python: bug['name'] in view.dependencyValues()">
+                    Bug1
+                  </option>
+                </div>
+              </select>
+              </td></tr></table>
             </div>
-          </select>
+          </div>
+        </div>
+    
+        <div class="row">
+          <div class="field">
+            <input type="submit" name="COLLAPSE" value="Collapse"
+                tal:condition="view/getShowDepsOptions"
+                i18n:attributes="value collapse-button" />
+    
+            <input type="submit" name="EXPAND" value="Expand" 
+                tal:condition="not: view/getShowDepsOptions"
+                i18n:attributes="value expand-button" />        
+          </div>
         </div>
-      </div>
-    </div>
-    <div class="row">
-      <input type="submit" name="submit" value="Change" 
-             i18n:attributes="value change-button" />
-    </div>
 
-  </form>
+      </form>
+      <div style="clear: both;"/>
+    </div></div>
+  </div>   
 
   <h4 i18n:translate="">Dependency Statistics</h4>
 


=== zopeproducts/bugtracker/browser/tracker.py 1.11 => 1.12 ===
--- zopeproducts/bugtracker/browser/tracker.py:1.11	Tue Aug 12 18:50:57 2003
+++ zopeproducts/bugtracker/browser/tracker.py	Thu Aug 28 01:22:31 2003
@@ -19,6 +19,7 @@
 from zope.app.browser.container.adding import Adding
 from zope.app.interfaces.dublincore import IZopeDublinCore
 from zope.app.interfaces.index.text import ISearchableText
+from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
 from zope.app.services.servicenames import Authentication
 from zope.app.traversing import getName
 from zope.component import getAdapter, getService
@@ -137,8 +138,12 @@
 
 def checkBug(bug, criteria, search_text):
     for name, values in criteria:
-        if values and not getattr(bug, name) in values:
-            return False
+        if name is 'owners':
+            if values and not filter(lambda u: u in bug.owners, values):
+                return False
+        else:
+            if values and not getattr(bug, name) in values:
+                return False
 
     # XXX: Extremely crude text search; should use indexes
     text = ' '.join(getAdapter(bug, ISearchableText).getSearchableText())
@@ -173,10 +178,18 @@
         auth = getService(self.context, Authentication)
         return auth.getPrincipal(self.context.submitter)
 
+    def owners(self):
+        return ', '.join(self.context.owners)
+
+    def shortCreated(self):
+        return self.created().split()[0]
 
 class Overview(object):
     """Overview of all the bugs."""
 
+    bug_listing_normal = ViewPageTemplateFile('bug_listing_normal.pt')
+    bug_listing_compressed = ViewPageTemplateFile('bug_listing_compressed.pt')
+
     # Tuple values:
     #   - collection name
     #   - Vocabulary Registry name
@@ -186,12 +199,15 @@
                    ('types', 'BugTypes', 'Type', 'type'),
                    ('releases', 'Releases', 'Release', 'release'),
                    ('priorities', 'Priorities', 'Priority', 'priority'),
+                   ('owners', 'Users', 'Owners', 'owners'),
                    )
 
     def getBugs(self):
         """Return a list of all bugs having a status listed in the parameter.
 
         If the parameter is an empty list/tuple, then show all bugs."""
+        if hasattr(self, '_bugs'):
+            return self._bugs
 
         criteria = []
         for collName, dummy1, dummy2, name in self.filter_vars:
@@ -208,7 +224,8 @@
         start = int(self.request.get('start', 0))
         size = int(self.request.get('size', 20))
                 
-        return Batch(result, start, size)
+        self._bugs =  Batch(result, start, size)
+        return self._bugs
 
     def updateSettings(self):
         for collName, dummy1, dummy2, dummy3 in self.filter_vars:
@@ -216,6 +233,8 @@
             self.request.response.setCookie('filter_'+collName,
                                             ', '.join(values))
         self.setSearchText()
+        self.setViewType()
+        self.setShowFilterOptions()
         return self.request.response.redirect('./overview.html')
 
     def getSettingsInfo(self):
@@ -235,6 +254,23 @@
     def setSearchText(self):
         value = self.request.get('search_text', '')
         self.request.response.setCookie('search_text', value)
+
+    def getViewType(self):
+        return self.request.cookies.get('view_type', 'normal')
+
+    def setViewType(self):
+        value = self.request.get('view_type', 'normal')
+        self.request.response.setCookie('view_type', value)
+
+    def getShowFilterOptions(self):
+        return int(self.request.cookies.get('show_filter_options', '1'))
+
+    def setShowFilterOptions(self):
+        if 'COLLAPSE' in self.request:
+            value = '0'
+        else:
+            value = '1'
+        self.request.response.setCookie('show_filter_options', value)
 
     def numberOfBugs(self):
         return len(self.context)


=== zopeproducts/bugtracker/browser/tracker_overview.pt 1.7 => 1.8 ===
--- zopeproducts/bugtracker/browser/tracker_overview.pt:1.7	Tue Aug 12 18:50:57 2003
+++ zopeproducts/bugtracker/browser/tracker_overview.pt	Thu Aug 28 01:22:31 2003
@@ -11,43 +11,80 @@
 <body>
 <div metal:fill-slot="body" tal:define="bugs view/getBugs">
 
-  <form action="updateOverviewSettings.html" method="post"
-      tal:define="settings view/getSettingsInfo">
-
-    <div class="row">
-      <div class="field">
-        Filter Text: 
-        <input type="text" name="search_text" value=""
-            tal:attributes="value view/getSearchText">
-      </div>
-    </div>
-
-    <div class="row">
-      <div class="field" tal:repeat="var settings">
-
-    <tal:block replace="var/title">Status</tal:block>:<br> 
-    <select size="5" name="stati:list" multiple="yes"
-        tal:attributes="name string:${var/name}:list">
-      <tal:block repeat="entry var/all">
-        <option value=""
-          tal:condition="python: entry.value in var['setting']"
-          tal:attributes="value entry/value"
-          tal:content="entry/title" selected="">New</option>
-        <option value=""
-          tal:condition="python: entry.value not in var['setting']"
-          tal:attributes="value entry/value"
-          tal:content="entry/title">New</option>
-      </tal:block>
-    </select>
-
-      </div>
-      <div class="field">
-        <input type="submit" value="Apply Filter" 
-            i18n:attributes="value save_filter-button" />
-      </div>
+  <div class="box">
+    <h4 style="padding: 0.3em">Filter Options</h4>
+    <div class="body">
+      <form action="updateOverviewSettings.html" method="post" 
+          class="even" style="padding: 0.5em;"
+          tal:define="settings view/getSettingsInfo">
+            
+        <div class="row"
+            tal:condition="view/getShowFilterOptions">
+          <div class="field">
+            <b>Filter Text</b>
+            <input type="text" name="search_text" value=""
+                tal:attributes="value view/getSearchText">
+          </div>
+          <div class="field">&nbsp;&nbsp;&nbsp;&nbsp;</div>
+          <div class="field">
+            <b>View Type</b>
+            <select name="view_type">
+              <tal:block repeat="vt python: ('normal', 'compressed')">
+                <option selected=""
+                    tal:content="vt"
+                    tal:attributes="value vt"
+                    tal:condition="python: view.getViewType() == vt" />
+                <option
+                    tal:content="vt"
+                    tal:attributes="value vt"
+                    tal:condition="python: view.getViewType() != vt" />
+              </tal:block>
+            </select>
+          </div>
+        </div>
+    
+        <div class="row"
+            tal:condition="view/getShowFilterOptions">
+          <div class="field" tal:repeat="var settings">
+    
+            <b tal:content="var/title">Status</b><br/>
+            <select size="5" name="stati:list" multiple="yes"
+                tal:attributes="name string:${var/name}:list">
+              <tal:block repeat="entry var/all">
+                <option value=""
+                  tal:condition="python: entry.value in var['setting']"
+                  tal:attributes="value entry/value"
+                  tal:content="entry/title" selected="">New</option>
+                <option value=""
+                  tal:condition="python: entry.value not in var['setting']"
+                  tal:attributes="value entry/value"
+                  tal:content="entry/title">New</option>
+              </tal:block>
+            </select>
+    
+          </div>
+        </div>
+        <div class="row">
+          <div class="field">
+            <input type="submit" value="Apply Filter/Changes" 
+                tal:condition="view/getShowFilterOptions"
+                i18n:attributes="value save-filter-changes-button" />
+          </div>
+          <div class="field">
+            <input type="submit" name="COLLAPSE" value="Collapse"
+                tal:condition="view/getShowFilterOptions"
+                i18n:attributes="value collapse-button" />
+    
+            <input type="submit" name="EXPAND" value="Expand" 
+                tal:condition="not: view/getShowFilterOptions"
+                i18n:attributes="value expand-button" />        
+          </div>
+        </div>
+        <div class="clear"/>
+    
+      </form>
     </div>
-
-  </form>
+  </div>
 
   <div class="row" i18n:domain="bugtracker">
     <div class="control">
@@ -89,49 +126,13 @@
     <div class="clear"></div> 
   </div>
 
-  <tal:block repeat="bug bugs" i18n:domain="bugtracker">
-    <div class=""
-        tal:define="oddrow repeat/bug/odd"
-        tal:attributes="class python:oddrow and 'even' or 'odd'">
-      <h5 class="summary_title" >
-        <a href="" 
-            tal:attributes="href string:./${bug/name}/@@overview.html"
-            i18n:translate="">
-          Bug #<d tal:replace="bug/name" i18n:name="bug_id">1</d> - 
-          <d tal:replace="bug/context/title" i18n:name="bug_title">
-            Bug Title
-          </d> 
-        </a>
-      </h5>
-
-      <div class="summary_content">
-        <div class="summary_condition">
-          <span i18n:translate="">Status:</span> 
-            <span tal:attributes="class bug/context/status" 
-                  tal:content="bug/status/title">New</span> - 
-          <span i18n:translate="">Priority:</span> 
-            <span tal:attributes="class bug/context/priority"
-                  tal:content="bug/priority/title">Normal</span> - 
-          <span i18n:translate="">Type: </span>
-            <b tal:replace="bug/type/title">Bug</b>
-        </div>
-
-        <div class="summary_body" tal:content="bug/descriptionPreview">
-          Message Description Sneak Preview goes here...
-        </div>
-
-        <div class="summary_metadata" i18n:translate="">
-          Posted by <b tal:content="bug/submitter/getTitle" 
-                       i18n:name="submitter">Submitter</b> 
-          on <b tal:replace="bug/created" 
-                i18n:name="created_date">2003/01/01</b>
-          - <b tal:replace="bug/numberOfComments" 
-               i18n:name="num_comments">3</b> comments
-        </div>
-      </div>
-    </div>
-
-  </tal:block>
+  <div 
+      tal:condition="python: view.getViewType() == 'normal'"
+      tal:replace="structure view/bug_listing_normal" />
+
+  <div 
+      tal:condition="python: view.getViewType() == 'compressed'"
+      tal:replace="structure view/bug_listing_compressed" />
 
   <div class="batch" tal:condition="bugs/startNumber" i18n:domain="bugtracker">
     <div class="prev_batch" tal:define="prev bugs/prevBatch">




More information about the Zope3-Checkins mailing list