Commits

Olemis Lang committed bbef9a8

BH Dashboard #566 : Optionally arrange product wells in columns inside product widgets. Two columns in global dashboard

Comments (0)

Files changed (2)

+t566_r1496958_product_widget_cols.diff

t566_r1496958_product_widget_cols.diff

+# HG changeset patch
+# Parent 3c1e652d3ebc360f9824fc1c507192f8df51b1aa
+BH Dashboard #566 : Arrange product wells in columns inside product widgets
+
+diff --git a/bloodhound_dashboard/bhdashboard/web_ui.py b/bloodhound_dashboard/bhdashboard/web_ui.py
+--- a/bloodhound_dashboard/bhdashboard/web_ui.py
++++ b/bloodhound_dashboard/bhdashboard/web_ui.py
+@@ -224,7 +224,8 @@
+                             'args': ['Timeline', None, {'args': {}}]
+                         },
+                     'products': {
+-                            'args': ['Product', None, {'args': {'max': 3}}]
++                            'args': ['Product', None, {'args': {'max': 3, 
++                                                                'cols': 2}}]
+                         },
+                }
+         }
+diff --git a/bloodhound_dashboard/bhdashboard/widgets/product.py b/bloodhound_dashboard/bhdashboard/widgets/product.py
+--- a/bloodhound_dashboard/bhdashboard/widgets/product.py
++++ b/bloodhound_dashboard/bhdashboard/widgets/product.py
+@@ -48,12 +48,11 @@
+         """Return a dictionary containing arguments specification for
+         the widget with specified name.
+         """
+-        return {
+-                'max' : {
+-                        'desc' : """Limit the number of products displayed""",
+-                        'type' : int
+-                    },
+-            }
++        return {'max' : {'desc' : """Limit the number of products displayed""",
++                         'type' : int},
++                'cols' : {'desc' : """Number of columns""",
++                          'type' : int}
++                }
+ 
+     get_widget_params = pretty_wrapper(get_widget_params, check_widget_name)
+ 
+@@ -116,8 +115,8 @@
+         data = {}
+         req = context.req
+         title = ''
+-        params = ('max', )
+-        max_, = self.bind_params(name, options, *params)
++        params = ('max', 'cols')
++        max_, cols = self.bind_params(name, options, *params)
+ 
+         if not isinstance(req.perm.env, ProductEnvironment):
+             for p in Product.select(self.env):
+@@ -136,6 +135,9 @@
+                     data.setdefault('product_list', []).append(p)
+             title = _('Products')
+ 
++        data['colseq'] = itertools.cycle(xrange(cols - 1, -1, -1)) if cols \
++                         else itertools.repeat(1)
++
+         return 'widget_product.html', \
+             {
+                 'title': title,
+diff --git a/bloodhound_dashboard/bhdashboard/widgets/templates/widget_product.html b/bloodhound_dashboard/bhdashboard/widgets/templates/widget_product.html
+--- a/bloodhound_dashboard/bhdashboard/widgets/templates/widget_product.html
++++ b/bloodhound_dashboard/bhdashboard/widgets/templates/widget_product.html
+@@ -22,60 +22,63 @@
+   xmlns:py="http://genshi.edgewall.org/"
+   xmlns:xi="http://www.w3.org/2001/XInclude">
+   <div py:if="product_list" class="row" id="products">
+-    <div py:for="p in product_list" class="span4">
+-      <div class="well product-well">
+-        <h4>
+-          &#9734; <a href="${req.href.products(p.prefix)}">$p.name ($p.prefix)</a>
+-          <py:if test="p.owner_link">
+-            <br />
+-            <small>owned by
+-              <a href="$p.owner_link">${authorinfo(p._data['owner']) if p._data['owner'] else _('(nobody)')}</a>
+-            </small>
+-          </py:if>
+-        </h4>
+-
+-        <h5>Milestones</h5>
+-        <py:choose test="">
+-          <py:when test="p.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>
+-            </ul>
+-          </py:when>
+-          <py:otherwise>
+-            (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>
++    <py:for each="i, p in zip(colseq, product_list)">
++      <div class="span4">
++        <div class="well product-well">
++          <h4>
++            &#9734; <a href="${req.href.products(p.prefix)}">$p.name ($p.prefix)</a>
++            <py:if test="p.owner_link">
++              <br />
++              <small>owned by
++                <a href="$p.owner_link">${authorinfo(p._data['owner']) if p._data['owner'] else _('(nobody)')}</a>
++              </small>
++            </py:if>
++          </h4>
++  
++          <h5>Milestones</h5>
++          <py:choose test="">
++            <py:when test="p.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>
++              </ul>
++            </py:when>
++            <py:otherwise>
++              (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>
++      <div class="clearfix" py:if="i == 0"/>
++    </py:for>
+   </div>
+ </div>
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.