Commits

Azoff committed 6c45a58

Added a few new testcases for Query.get_href().
Fixed Query.template_data() to use the new order format.
Fixed so that the first field to order by is always indicated by a litle
triangle, the rest of the order fields are currently NOT visible in the UI.

Comments (0)

Files changed (1)

      def count(self, req=None, db=None, cached_ids=None, authname=None,
                tzinfo=None, locale=None):
          """Get the number of matching tickets for the present query.
-@@ -393,9 +422,13 @@ class Query(object):
+@@ -393,9 +422,14 @@ class Query(object):
  
          if id is None:
              id = self.id
 -            desc = self.desc
 -        if order is None:
 +        if order:
-+            # If order, also use the passed desc
-+            order = '-' + order if desc else order
++            if isinstance(order, basestring):
++                # If order, also use the passed desc
++                order = ['-' + order if desc else order]
 +        elif self.group:
 +            # First item is the group...
 +            order = self.order[1:]
              order = self.order
          if max is None:
              max = self.max
-@@ -422,9 +455,8 @@ class Query(object):
+@@ -422,9 +456,8 @@ class Query(object):
          
          return href.query(constraints,
                            report=id,
 -                          order=order, desc=1 if desc else None,
 -                          group=self.group,
 -                          groupdesc=1 if self.groupdesc else None,
-+                          order=order,
++                          order='|'.join(order),
 +                          group=self.order[0] if self.group else None,
                            col=cols,
                            row=self.rows,
                            max=max,
-@@ -458,11 +490,10 @@ class Query(object):
+@@ -458,11 +491,10 @@ class Query(object):
              for col in args:
                  if not col in cols:
                      cols.append(col)
          cols.extend([c for c in self.constraint_cols if not c in cols])
  
          custom_fields = [f['name'] for f in self.fields if f.get('custom')]
-@@ -483,14 +514,13 @@ class Query(object):
+@@ -483,14 +515,13 @@ class Query(object):
  
          # Join with the enum table for proper sorting
          for col in [c for c in enum_columns
              sql.append("\n  LEFT OUTER JOIN %s ON (%s.name=%s)"
                         % (col, col, col))
  
-@@ -641,11 +671,10 @@ class Query(object):
+@@ -641,11 +672,10 @@ class Query(object):
                             (','.join([str(id) for id in cached_ids])))
              
          sql.append("\nORDER BY ")
              if name in enum_columns:
                  col = name + '.value'
              elif name in custom_fields:
-@@ -673,10 +702,11 @@ class Query(object):
+@@ -673,10 +703,11 @@ class Query(object):
                             % (desc, desc, col, desc))
              else:
                  sql.append("%s%s" % (col, desc))
  
          if errors:
              raise QueryValueError(errors)
-@@ -760,6 +790,7 @@ class Query(object):
+@@ -734,11 +765,16 @@ class Query(object):
+         wikify = set(f['name'] for f in self.fields 
+                      if f['type'] == 'text' and f.get('format') == 'wiki')
+ 
++        def get_order_for_col(col):
++            for field, desc in self.get_order():
++                if field == col:
++                    return '-' + field if not desc else field
++            return col
++                    
+         headers = [{
+             'name': col, 'label': labels.get(col, _('Ticket')),
+             'wikify': col in wikify,
+-            'href': self.get_href(context.href, order=col,
+-                                  desc=(col == self.order and not self.desc))
++            'href': self.get_href(context.href, order=[get_order_for_col(col)])
+         } for col in cols]
+ 
+         fields = {'id': {'type': 'id', 'label': _("Ticket")}}
+@@ -760,6 +796,7 @@ class Query(object):
                      for (label, milestones) in groups]
              fields[name] = field
  
          groups = {}
          groupsequence = []
          for ticket in tickets:
-@@ -770,8 +801,8 @@ class Query(object):
+@@ -770,8 +807,8 @@ class Query(object):
                      ticket['added'] = True
                  elif ticket['changetime'] > orig_time:
                      ticket['changed'] = True
                  groups.setdefault(group_key, []).append(ticket)
                  if not groupsequence or group_key not in groupsequence:
                      groupsequence.append(group_key)
-@@ -861,15 +892,19 @@ class QueryModule(Component):
+@@ -861,15 +898,19 @@ class QueryModule(Component):
      default_columns = ListOption('query', 'default_columns',
          default=None,
          doc="""List of columns to show in query unless defined by the query.
  
      # IContentConverter methods
  
-@@ -932,10 +967,6 @@ class QueryModule(Component):
+@@ -932,10 +973,6 @@ class QueryModule(Component):
                  query = Query.from_string(self.env, qstring)
                  args = {'order': query.order, 'group': query.group,
                          'col': query.cols, 'max': query.max}
                  constraints = query.constraints
  
              # Substitute $USER, or ensure no field constraints that depend
-@@ -949,6 +980,18 @@ class QueryModule(Component):
+@@ -949,6 +986,18 @@ class QueryModule(Component):
                              del clause[field]
                              break
  
          cols = args.get('col')
          if isinstance(cols, basestring):
              cols = [cols]
-@@ -963,13 +1006,11 @@ class QueryModule(Component):
+@@ -963,13 +1012,11 @@ class QueryModule(Component):
          max = args.get('max')
          if max is None and format in ('csv', 'tab'):
              max = 0 # unlimited unless specified explicitly
  
          if 'update' in req.args:
              # Reset session vars
-@@ -1423,19 +1464,21 @@ class TicketQueryMacro(WikiMacroBase):
+@@ -1423,19 +1470,21 @@ class TicketQueryMacro(WikiMacroBase):
  
          def ticket_groups():
              groups = []
                  href = q.get_href(formatter.context)
                  groups.append((v, [t for t in g], href, title))
              return groups
-@@ -1456,7 +1499,7 @@ class TicketQueryMacro(WikiMacroBase):
+@@ -1456,7 +1505,7 @@ class TicketQueryMacro(WikiMacroBase):
                      [(tag.p(tag_('%(groupvalue)s %(groupname)s tickets:',
                                   groupvalue=tag.a(v, href=href, class_='query',
                                                    title=title),
            <label for="groupdesc">descending</label>
          </p>
  
+@@ -210,7 +210,7 @@
+ 
+         <div class="buttons">
+           <input py:if="report_resource" type="hidden" name="report" value="$report_resource.id" />
+-          <input type="hidden" name="order" value="$query.order" />
++          <input type="hidden" name="order" value="${'|'.join(query.order[1 if query.group else 0:])}" />
+           <input py:if="query.desc" type="hidden" name="desc" value="1" />
+           <input type="submit" name="update" value="${_('Update')}" />
+         </div>
 diff --git a/trac/ticket/templates/query_results.html b/trac/ticket/templates/query_results.html
 --- a/trac/ticket/templates/query_results.html
 +++ b/trac/ticket/templates/query_results.html
-@@ -24,8 +24,8 @@
+@@ -24,19 +24,20 @@
    <py:def function="group_heading(groupname, results)">
      <h2 class="report-result" py:if="groupname is not None"
          i18n:msg="grouplabel, groupname, count"
                   count = ngettext('%(num)s match', '%(num)s matches', len(results))">
        ${grouplabel}: ${groupname} <span class="numrows">(${count})</span>
      </h2>
+   </py:def>
+   <py:def function="column_headers()">
++    <?python order = query.get_order()[1 if query.group else 0] ?>
+     <tr class="trac-columns">
+       <th py:for="header in headers"
+-          class="$header.name${(' desc' if query.desc else ' asc') if query.order == header.name else ''}">
++          class="$header.name${(' desc' if order[1] else ' asc') if order[0] == header.name else ''}">
+         <?python asc = _('(ascending)'); desc = _('(descending)') ?>
+         <a title="${_('Sort by %(col)s %(direction)s', col=header.label,
+-                      direction=(desc if query.order == header.name and not query.desc else asc))}"
++                      direction=(desc if order[0] == header.name and not order[1] else asc))}"
+            href="$header.href">${header.label}</a>
+       </th>
+     </tr>
 diff --git a/trac/ticket/tests/query.py b/trac/ticket/tests/query.py
 --- a/trac/ticket/tests/query.py
 +++ b/trac/ticket/tests/query.py
  
      def test_default_cols_with_config_no_request(self):
          self.env.config.set('query', 'default_columns', 'id,time,changetime,summary,milestone,type')
-@@ -741,6 +747,17 @@ ORDER BY COALESCE(priority.value,'')='',
+@@ -741,6 +747,49 @@ ORDER BY COALESCE(priority.value,'')='',
          self.assertEqual([], args)
          tickets = query.execute(self.req)
  
 +        query = Query(self.env, group='-milestone', order=['-priority', 'id'])
 +        self.assertEqual(True, query.group)
 +        self.assertEqual(('milestone', True), query.get_group())
++        
++    def test_get_href_1(self):
++        query = Query(self.env, group='milestone', order='type')
++        self.assertEqual('foo/query?group=milestone&order=type', query.get_href(Href('foo')))
++        
++    def test_get_href_2(self):
++        query = Query(self.env, group='milestone', order=['type', '-id'])
++        self.assertEqual('/query?group=milestone&order=type%7C-id', query.get_href(Href('')))
++        
++    def test_get_href_3(self):
++        query = Query(self.env, group='milestone', order=['-type', '-time'])
++        self.assertEqual('/query?group=milestone&order=foo', query.get_href(Href(''), order='foo'))
++        
++    def test_get_href_4(self):
++        query = Query(self.env, group='milestone', order=['-type', '-time'])
++        self.assertEqual('/query?group=milestone&order=-foo', query.get_href(Href(''), order=['-foo']))
++        
++    def test_get_href_5(self):
++        query = Query(self.env, group='milestone', order=['-type', '-time'])
++        self.assertEqual('/query?group=milestone&order=-foo', query.get_href(Href(''), order='-foo'))
++        
++    def test_get_href_6(self):
++        query = Query(self.env, group='milestone', order=['-type', '-time'])
++        self.assertEqual('/query?group=milestone&order=-foo', query.get_href(Href(''), order='foo', desc=1))
++        
++    def test_get_href_7(self):
++        query = Query(self.env, group='milestone', order=['-type', '-time'])
++        self.assertEqual('/query?group=milestone&order=foo%7C-bar', query.get_href(Href(''), order=['foo', '-bar'], desc=1))
++        
++    def test_get_href_8(self):
++        query = Query(self.env, group='milestone', cols=['id', 'type', 'time'])
++        self.assertEqual('/query?group=milestone&order=priority&col=id&col=type&col=time', query.get_href(Href('')))
 +
      def test_csv_escape(self):
          query = Mock(get_columns=lambda: ['col1'],