Author: matevz
Date: Thu Mar 21 13:25:19 2013
New Revision: 1459300

URL: http://svn.apache.org/r1459300
Log:
#325 - Multiproduct UI: Dashboard (versions and components added to product 
well)

Modified:
    
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_dashboard/bhdashboard/widgets/product.py
    
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_dashboard/bhdashboard/widgets/templates/widget_product.html
    
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_theme/bhtheme/htdocs/bloodhound.css

Modified: 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_dashboard/bhdashboard/widgets/product.py
URL: 
http://svn.apache.org/viewvc/incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_dashboard/bhdashboard/widgets/product.py?rev=1459300&r1=1459299&r2=1459300&view=diff
==============================================================================
--- 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_dashboard/bhdashboard/widgets/product.py
 (original)
+++ 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_dashboard/bhdashboard/widgets/product.py
 Thu Mar 21 13:25:19 2013
@@ -24,8 +24,10 @@ r"""Project dashboard for Apache(TM) Blo
 Widgets displaying product information (multiproduct).
 """
 
+import itertools
+
 from trac.util.translation import _
-from trac.ticket.model import Milestone
+from trac.ticket.model import Milestone, Component, Version
 from trac.ticket.query import Query
 
 from bhdashboard.util import WidgetBase, check_widget_name, pretty_wrapper
@@ -52,49 +54,57 @@ class ProductWidget(WidgetBase):
 
     get_widget_params = pretty_wrapper(get_widget_params, check_widget_name)
 
-    def _get_product_milestones(self, req, product, max_):
-        def new_milestone(env, name, url, ticket_count=None):
-            m = Milestone(env)
-            m.name = name
-            m.url = url
-            m.ticket_count = ticket_count
-            return m
-
+    def _get_product_info(self, product, resource, max_):
         penv = ProductEnvironment(self.env, product.prefix)
         href = ProductizedHref(self.env, penv.href.base)
-        milestones = []
+        results = []
 
-        mquery = Milestone.select(penv)
-        for m in mquery[:max_]:
-            m.url = href.milestone(m.name)
-            m.ticket_count = penv.db_query(
-                'SELECT count(*) FROM ticket WHERE milestone="%s" '
-                'AND status <> "closed"' % m.name)[0][0]
-            milestones.append(m)
+        # some queries return a list/tuple, some a generator,
+        # hence count() to get the result length
+        def count(iter_):
+            try:
+                return len(iter_)
+            except TypeError:
+                return sum(1 for _ in iter_)
+
+        query = resource['type'].select(penv)
+        for q in itertools.islice(query, max_):
+            q.url = href(resource['name'], q.name) if resource.get('hrefurl') \
+                else Query.from_string(penv, 'order=priority&%s=%s' %
+                    (resource['name'], q.name)).get_href(href)
+            q.ticket_count = penv.db_query(
+                'SELECT COUNT(*) FROM ticket WHERE %s="%s" '
+                'AND status <> "closed"' % (resource['name'], q.name))[0][0]
+            results.append(q)
 
-        # add a '(No milestone)' entry if there are tickets
-        # without an assigned milestone in the product
+        # add a '(No <milestone/component/version>)' entry if there are
+        # tickets without an assigned resource in the product
         ticket_count = penv.db_query(
-            'SELECT count(*) FROM ticket WHERE milestone="" '
-            'AND status <> "closed"')[0][0]
+            'SELECT COUNT(*) FROM ticket WHERE %s="" '
+            'AND status <> "closed"' % (resource['name'],))[0][0]
         if ticket_count != 0:
-            milestones.append(new_milestone(penv, _('(No milestone)'),
-                Query.from_string(penv,
-                    'status=!closed&col=id&col=summary&col=owner'
-                    '&col=status&col=priority&order=priority&milestone='
-                ).get_href(href),
-                ticket_count))
-
-        milestones.sort(key=lambda x: x.ticket_count, reverse=True)
-
-        # add a link to the milestone list if there are
-        # more than max milestones defined
-        if len(mquery) > max_:
-            milestones.append(new_milestone(penv, _('... more'),
-                href.milestone(), None))
-
-        return milestones
+            q = resource['type'](penv)
+            q.name = '(No %s)' % (resource['name'],)
+            q.url = Query.from_string(penv,
+                        'status=!closed&col=id&col=summary&col=owner'
+                        '&col=status&col=priority&order=priority&%s=' %
+                        (resource['name'],)).get_href(href)
+            q.ticket_count = ticket_count
+            results.append(q)
+
+        results.sort(key=lambda x: x.ticket_count, reverse=True)
+
+        # add a link to the resource list if there are
+        # more than max resources defined
+        if count(query) > max_:
+            q = resource['type'](penv)
+            q.name = _('... more')
+            q.ticket_count = None
+            q.url = href(resource['name']) if resource.get('hrefurl') \
+                else href.product(product.prefix)
+            results.append(q)
 
+        return results
 
     def render_widget(self, name, context, options):
         """Gather product list and render data in compact view
@@ -108,7 +118,13 @@ class ProductWidget(WidgetBase):
         if not isinstance(req.perm.env, ProductEnvironment):
             for p in Product.select(self.env):
                 if 'PRODUCT_VIEW' in req.product_perm(p.prefix):
-                    p.milestones = self._get_product_milestones(req, p, max_)
+                    for resource in (
+                        { 'type': Milestone, 'name': 'milestone', 'hrefurl': 
True },
+                        { 'type': Component, 'name': 'component' },
+                        { 'type': Version, 'name': 'version' },
+                    ):
+                        setattr(p, resource['name'] + 's',
+                            self._get_product_info(p, resource, max_))
                     data.setdefault('product_list', []).append(p)
             title = _('Products')
 

Modified: 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_dashboard/bhdashboard/widgets/templates/widget_product.html
URL: 
http://svn.apache.org/viewvc/incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_dashboard/bhdashboard/widgets/templates/widget_product.html?rev=1459300&r1=1459299&r2=1459300&view=diff
==============================================================================
--- 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_dashboard/bhdashboard/widgets/templates/widget_product.html
 (original)
+++ 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_dashboard/bhdashboard/widgets/templates/widget_product.html
 Thu Mar 21 13:25:19 2013
@@ -24,10 +24,11 @@
   <div py:if="product_list" class="row" id="products">
     <div py:for="p in product_list" class="span3 well product-well">
       <h4>&#9734; <a href="${req.href.products(p.prefix)}">$p.name 
($p.prefix)</a></h4>
-      <h5 class="milestone-title">Milestones</h5>
+
+      <h5>Milestones</h5>
       <py:choose test="">
         <py:when test="p.milestones">
-          <ul py:if="p.milestones" class="milestones">
+          <ul class="subset">
             <li py:for="m in p.milestones">
               <a href="$m.url">$m.name<py:if test="m.ticket_count is not 
None"> ($m.ticket_count)</py:if></a>
             </li>
@@ -37,6 +38,34 @@
           (No milestones for this product)
         </py:otherwise>
       </py:choose>
+
+      <h5>Components</h5>
+      <py:choose test="">
+        <py:when test="p.components">
+          <ul class="subset">
+            <li py:for="c in p.components">
+              <a href="$c.url">$c.name<py:if test="c.ticket_count is not 
None"> ($c.ticket_count)</py:if></a>
+            </li>
+          </ul>
+        </py:when>
+        <py:otherwise>
+          (No components for this product)
+        </py:otherwise>
+      </py:choose>
+
+      <h5>Versions</h5>
+      <py:choose test="">
+        <py:when test="p.versions">
+          <ul class="subset">
+            <li py:for="v in p.versions">
+              <a href="$v.url">$v.name<py:if test="v.ticket_count is not 
None"> ($v.ticket_count)</py:if></a>
+            </li>
+          </ul>
+        </py:when>
+        <py:otherwise>
+          (No versions for this product)
+        </py:otherwise>
+      </py:choose>
     </div>
   </div>
 </div>

Modified: 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_theme/bhtheme/htdocs/bloodhound.css
URL: 
http://svn.apache.org/viewvc/incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_theme/bhtheme/htdocs/bloodhound.css?rev=1459300&r1=1459299&r2=1459300&view=diff
==============================================================================
--- 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_theme/bhtheme/htdocs/bloodhound.css
 (original)
+++ 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_theme/bhtheme/htdocs/bloodhound.css
 Thu Mar 21 13:25:19 2013
@@ -1123,9 +1123,9 @@ table.wiki th {
   padding: 10px;
 }
 
-#products .milestones {
+#products .subset {
   list-style-type: none;
-  margin: 0;
+  margin: 0 0 10px 0;
   padding: 0;
 }
 


Reply via email to