Merge lp:~adeuring/launchpad/bug-201015-bug-branch-search into lp:launchpad/db-devel

Proposed by Abel Deuring
Status: Merged
Merged at revision: not available
Proposed branch: lp:~adeuring/launchpad/bug-201015-bug-branch-search
Merge into: lp:launchpad/db-devel
Diff against target: 647 lines (+273/-96)
9 files modified
lib/canonical/launchpad/icing/style.css (+11/-1)
lib/lp/bugs/browser/bugtask.py (+14/-4)
lib/lp/bugs/doc/bugtask-search.txt (+27/-1)
lib/lp/bugs/interfaces/bugtarget.py (+1/-1)
lib/lp/bugs/interfaces/bugtask.py (+32/-2)
lib/lp/bugs/model/bugtarget.py (+1/-1)
lib/lp/bugs/model/bugtask.py (+22/-7)
lib/lp/bugs/stories/bugtask-searches/xx-filter-by-linked-branches.txt (+64/-0)
lib/lp/bugs/templates/bugtask-macros-tableview.pt (+101/-79)
To merge this branch: bzr merge lp:~adeuring/launchpad/bug-201015-bug-branch-search
Reviewer Review Type Date Requested Status
Curtis Hovey (community) Approve
Review via email: mp+19699@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Abel Deuring (adeuring) wrote :

This branch is a fix of bug 201015: "Cannot search for bugs with Bazaar branches"

implementation details:

- added an enumeration BugBranchSearch to lp.bugs.interfaces.bugtask
- added a new constructor parameter and a new property "linked_branches" to class BugTaskSearchParams
- code in BugTaskSet.search() to generate an SQL clause for the new search option.
- added a Choice field with BugBranchSearch as a vocabulary to the interface class for the data of the "advanced bug search" form
- told the browser class for the "advanced bug search" to use a radio button widget for the new input filed "search for bugs having [no] linked branches"
- tests of BugTaskSet.search() (via IProduct.searchTasks()) for the new search option
- a short story test for the "presentation" of the new search option

UI note: I wanted to place the new radio buttons close to the existing input field "Show only bugs with patches available", since the new option has a similar purpose. This makes the right column of the table "other options" much longer that the left column, which is aesthetically not very appealing. I considered to move the options "Show only bugs associated with a CVE" and "Show only bugs affecting me" into the left column, but did not do this, because myself would be a bit confused by the changed layout, i.e., I would need a few extra seconds to find the options in their slightly changed location, when doing a bug search...

./bin/test -t bugtask-search.txt
./bin/test -t xx-filter-by-linked-branches.txt

no lint

Revision history for this message
Curtis Hovey (sinzui) wrote :
Download full text (4.2 KiB)

Hi Abel.

I am sorry you had to touch this page and that I am the reviewer; this
page has irked me for a long time because it does not look consistent
with the rest of Launchpad. Instead of asking you to fix this page, I
will propose code and text fixes that I think are easy to make.

There are some general problems that are never being addresses when
we update this page. I really want to take the time to fix the general
problem with this branch, and you get to close some extra bugs too:

    * Hard to scan. There is not enough white-space in the layout and
      all the text is the same weight and size. Information is lost
      like a tree in a forest.
    * Labels/legends do not match their field content.
    * We have added to this page without ever asking if we need
      to rearrange to the order of the sections to match what users
      want to use.

Your screenshot illustrated these three problems. Notice that the
Tags any/all radio buttons look like there are subordinate to
Show only bugs affecting me. I also question why some checkbox text are
bold and others are normal.

What follows is my analysis and proposed fix: you can see a see a picture
and patch at:
    http://people.canonical.com/~curtis/bug-search.png
    http://people.canonical.com/~curtis/bug-search.patch

My assumption was that the primary problem with this form is that
it is crafted rather than generated. After investigating how I could
make this better, I know understand this issue is really one of
markup+css neglect. All pages that use <legend> in a collapsible field
except this one. They are used to add an expansible section to a form.
This page is intended to be long with all sections visible. We do not
have css rules for this page!

    * In style.css, replace
        legend {font-weight: bold;}

      with
        .long td {
            padding-right: 1em;
            }
        .long fieldset {
            margin-top: 1em;
            }
        .long legend {
            color: #666;
            font-weight: bold;
            font-size: 123.1%;
            }

     * In bugtask-macros-tableview.pt, update the form class in
       <metal:advanced_search_form define-macro="advanced_search_form"> from
          <form class="lesser" name="search" method="get" action="">

       to
          <form class="long" name="search" method="get" action="">

We do not want to use the .lesser class because this page is not showing
a long listing, and it is forcing all the text to be the same small font.
We are replacing the css rules for this page with rules that create space
between the sections and make each section distinct.

As for the legend text and sections:

    * Series-specific => Milestones, components, and tags
      * Remove the width="40%" rules from the <td> and the remove the
        empty <td>.
      * Move tags below milestones and components
      * Use <td span="2"> so that the layout can fit the space:
        Move the help to the right of the input,
        Move the radio button below the field that controls them.

    * Other => Bug relationships
      * Move the "Show ..." group of option to the first column,
        and make your addition to the bottom
 ...

Read more...

review: Needs Fixing (ui)
Revision history for this message
Abel Deuring (adeuring) wrote :
Download full text (6.3 KiB)

Hi Curtis,

thanks for the improvements of the search page!

On 19.02.2010 19:06, Curtis Hovey wrote:
> Review: Needs Fixing ui
> Hi Abel.
>
> I am sorry you had to touch this page and that I am the reviewer; this
> page has irked me for a long time because it does not look consistent
> with the rest of Launchpad. Instead of asking you to fix this page, I
> will propose code and text fixes that I think are easy to make.
>
> There are some general problems that are never being addresses when
> we update this page. I really want to take the time to fix the general
> problem with this branch, and you get to close some extra bugs too:
>
> * Hard to scan. There is not enough white-space in the layout and
> all the text is the same weight and size. Information is lost
> like a tree in a forest.
> * Labels/legends do not match their field content.
> * We have added to this page without ever asking if we need
> to rearrange to the order of the sections to match what users
> want to use.
>
> Your screenshot illustrated these three problems. Notice that the
> Tags any/all radio buttons look like there are subordinate to
> Show only bugs affecting me. I also question why some checkbox text are
> bold and others are normal.
>
> What follows is my analysis and proposed fix: you can see a see a picture
> and patch at:
> http://people.canonical.com/~curtis/bug-search.png
> http://people.canonical.com/~curtis/bug-search.patch

I applied your patch.

>
> My assumption was that the primary problem with this form is that
> it is crafted rather than generated. After investigating how I could
> make this better, I know understand this issue is really one of
> markup+css neglect. All pages that use <legend> in a collapsible field
> except this one. They are used to add an expansible section to a form.
> This page is intended to be long with all sections visible. We do not
> have css rules for this page!
>
> * In style.css, replace
> legend {font-weight: bold;}
>
> with
> .long td {
> padding-right: 1em;
> }
> .long fieldset {
> margin-top: 1em;
> }
> .long legend {
> color: #666;
> font-weight: bold;
> font-size: 123.1%;
> }
>
> * In bugtask-macros-tableview.pt, update the form class in
> <metal:advanced_search_form define-macro="advanced_search_form"> from
> <form class="lesser" name="search" method="get" action="">
>
> to
> <form class="long" name="search" method="get" action="">
>
> We do not want to use the .lesser class because this page is not showing
> a long listing, and it is forcing all the text to be the same small font.
> We are replacing the css rules for this page with rules that create space
> between the sections and make each section distinct.
>
> As for the legend text and sections:
>
> * Series-specific => Milestones, components, and tags
> * Remove the width="40%" rules from the <td> and the remove the
> empty <td>.
> * Move tags below milestones and components
> * Use <td span="2"> so...

Read more...

Revision history for this message
Abel Deuring (adeuring) wrote :

A screenshot of the the searhc page: http://people.canonical.com/~adeuring/branchsearch.png

Revision history for this message
Curtis Hovey (sinzui) wrote :

Hi Abel

  review: approve

On Tue, 2010-02-23 at 09:54 +0000, Abel Deuring wrote:
> Hi Curtis,
...
> I added two checkboxes "Show bugs with[out] branches" below "Show only
> bugs with patches available".
>
> We had on Friday a short discussion on IRC if searching for bugs without
> branches is important enough. I think it is: We want to improve the
> relations with upstream project, and people working on upstream projects
> can find the most autoritative answer to what code is used in Ubuntu in
> Bazaar branches. On the other hand, a link between a branch and bug must
> be manually created by an Ubuntu developer, and this is quite easy to
> forget (I am a good example that this can happen quite often ;) So,
> being able to get a list of bugs in the states "fix commited" and "fix
> released" but having no linked branches allows Ubuntu developers to add
> possibly missing links betwwen branches and bugs, thus making live
> easier for upstream.
>
> Also, we discussed if radio button should be used to select the options
> "search for bugs with/without branches/search all bugs". Deryck proposed
> to use checkboxes instead, and while I would prefer radio buttons,
> because they describe more precisely the three possible options,
> checkboxes are of course more consistent with the other interfaces
> elements of the page.

Yes, a radio button is correct in this case. Your screenshot of two
mutually exclusive checkboxes selected shows we are encouraging users to
ask the impossible. I think the layout was the underlying reason to
change the control. This layout is much nicer and the position of the
two radio buttons will make the intent clear.

--
__Curtis C. Hovey_________
http://launchpad.net/

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/icing/style.css'
2--- lib/canonical/launchpad/icing/style.css 2010-02-21 20:46:26 +0000
3+++ lib/canonical/launchpad/icing/style.css 2010-02-25 08:53:48 +0000
4@@ -84,7 +84,17 @@
5 outline: 1px #666;
6 }
7 label {white-space: nowrap;}
8-legend {font-weight: bold;}
9+.long td {
10+ padding-right: 1em;
11+ }
12+.long fieldset {
13+ margin-top: 1em;
14+ }
15+.long legend {
16+ color: #666;
17+ font-weight: bold;
18+ font-size: 123.1%;
19+ }
20 .listbox { /* a scrolling list of checkboxes or radio buttons */
21 border: 1px solid #8cacbb;
22 display: inline-block;
23
24=== modified file 'lib/lp/bugs/browser/bugtask.py'
25--- lib/lp/bugs/browser/bugtask.py 2010-02-20 13:16:38 +0000
26+++ lib/lp/bugs/browser/bugtask.py 2010-02-25 08:53:48 +0000
27@@ -103,8 +103,9 @@
28 BugNominationStatus, IBugNominationSet)
29 from lp.bugs.interfaces.bug import IBug, IBugSet
30 from lp.bugs.interfaces.bugtask import (
31- BugTagsSearchCombinator, BugTaskImportance, BugTaskSearchParams,
32- BugTaskStatus, BugTaskStatusSearchDisplay, IBugTask, IBugTaskSearch,
33+ BugBranchSearch, BugTagsSearchCombinator, BugTaskImportance,
34+ BugTaskSearchParams, BugTaskStatus, BugTaskStatusSearchDisplay,
35+ DEFAULT_SEARCH_BUGTASK_STATUSES_FOR_DISPLAY, IBugTask, IBugTaskSearch,
36 IBugTaskSet, ICreateQuestionFromBugTaskForm, IDistroBugTask,
37 IDistroSeriesBugTask, IFrontPageBugTaskSearch,
38 INominationsReviewTableBatchNavigator, INullBugTask, IPersonBugTaskSearch,
39@@ -2324,6 +2325,16 @@
40 if has_patch:
41 data["attachmenttype"] = BugAttachmentType.PATCH
42
43+ has_branches = data.get('has_branches', True)
44+ has_no_branches = data.get('has_no_branches', True)
45+ if has_branches and not has_no_branches:
46+ data['linked_branches'] = BugBranchSearch.BUGS_WITH_BRANCHES
47+ elif not has_branches and has_no_branches:
48+ data['linked_branches'] = (
49+ BugBranchSearch.BUGS_WITHOUT_BRANCHES)
50+ else:
51+ data['linked_branches'] = BugBranchSearch.ALL
52+
53 # Filter appropriately if the user wants to restrict the
54 # search to only bugs with no package information.
55 has_no_package = data.pop("has_no_package", False)
56@@ -2501,14 +2512,13 @@
57 dict(
58 value=term.token, title=term.title or term.token,
59 checked=term.value in default_values))
60-
61 return helpers.shortlist(widget_values, longest_expected=10)
62
63 def getStatusWidgetValues(self):
64 """Return data used to render the status checkboxes."""
65 return self.getWidgetValues(
66 vocabulary=BugTaskStatusSearchDisplay,
67- default_values=UNRESOLVED_BUGTASK_STATUSES)
68+ default_values=DEFAULT_SEARCH_BUGTASK_STATUSES_FOR_DISPLAY)
69
70 def getImportanceWidgetValues(self):
71 """Return data used to render the Importance checkboxes."""
72
73=== modified file 'lib/lp/bugs/doc/bugtask-search.txt'
74--- lib/lp/bugs/doc/bugtask-search.txt 2010-02-11 05:08:47 +0000
75+++ lib/lp/bugs/doc/bugtask-search.txt 2010-02-25 08:53:48 +0000
76@@ -962,10 +962,36 @@
77 >>> print reduce(
78 ... lambda x, y: x and y,
79 ... [task.bug.isUserAffected(foo_bar)
80- ... for task in firefox.searchTasks(search_params)])
81+ ... for task in firefox.searchTasks(search_params)])
82 True
83
84
85+== Searching for bugs linked to branches ==
86+
87+We can search for bugs having branches linked to them.
88+
89+ >>> from lp.bugs.interfaces.bugtask import BugBranchSearch
90+ >>> search_params = BugTaskSearchParams(
91+ ... user=None, linked_branches=BugBranchSearch.BUGS_WITH_BRANCHES)
92+ >>> for task in firefox.searchTasks(search_params):
93+ ... print task.bug.id, task.bug.linked_branches.count()
94+ 4 2
95+ 5 1
96+
97+Similary, we can search for bugs that do not have any linked branches.
98+
99+ >>> from lp.bugs.interfaces.bugtask import BugBranchSearch
100+ >>> search_params = BugTaskSearchParams(
101+ ... user=None, linked_branches=BugBranchSearch.BUGS_WITHOUT_BRANCHES)
102+ >>> for task in firefox.searchTasks(search_params):
103+ ... print task.bug.id, task.bug.linked_branches.count()
104+ 1 0
105+ 6 0
106+ 18 0
107+ 20 0
108+ 21 0
109+
110+
111 == Ordering search results ==
112
113 The result returned by bugtask searches can come sorted by a specified order
114
115=== modified file 'lib/lp/bugs/interfaces/bugtarget.py'
116--- lib/lp/bugs/interfaces/bugtarget.py 2010-01-21 22:43:19 +0000
117+++ lib/lp/bugs/interfaces/bugtarget.py 2010-02-25 08:53:48 +0000
118@@ -179,7 +179,7 @@
119 hardware_owner_is_bug_reporter=None,
120 hardware_owner_is_affected_by_bug=False,
121 hardware_owner_is_subscribed_to_bug=False,
122- hardware_is_linked_to_bug=False):
123+ hardware_is_linked_to_bug=False, linked_branches=None):
124 """Search the IBugTasks reported on this entity.
125
126 :search_params: a BugTaskSearchParams object
127
128=== modified file 'lib/lp/bugs/interfaces/bugtask.py'
129--- lib/lp/bugs/interfaces/bugtask.py 2010-02-08 17:00:55 +0000
130+++ lib/lp/bugs/interfaces/bugtask.py 2010-02-25 08:53:48 +0000
131@@ -9,6 +9,7 @@
132
133 __all__ = [
134 'BUG_SUPERVISOR_BUGTASK_STATUSES',
135+ 'BugBranchSearch',
136 'BugTagsSearchCombinator',
137 'BugTaskImportance',
138 'BugTaskSearchParams',
139@@ -16,6 +17,7 @@
140 'BugTaskStatusSearch',
141 'BugTaskStatusSearchDisplay',
142 'ConjoinedBugTaskEditError',
143+ 'DEFAULT_SEARCH_BUGTASK_STATUSES_FOR_DISPLAY',
144 'IAddBugTaskForm',
145 'IAddBugTaskWithProductCreationForm',
146 'IBugTask',
147@@ -273,6 +275,20 @@
148 use_template(BugTaskStatusSearch, exclude=('INCOMPLETE'))
149
150
151+class BugBranchSearch(EnumeratedType):
152+ """Bug branch search option.
153+
154+ The possible values to search for bugs having branches attached
155+ or not having branches attched.
156+ """
157+
158+ ALL = Item("Show all bugs")
159+
160+ BUGS_WITH_BRANCHES = Item("Show only Bugs with linked Branches")
161+
162+ BUGS_WITHOUT_BRANCHES = Item("Show only Bugs without linked Branches")
163+
164+
165 # XXX: Brad Bollenbach 2005-12-02 bugs=5320:
166 # In theory, INCOMPLETE belongs in UNRESOLVED_BUGTASK_STATUSES, but the
167 # semantics of our current reports would break if it were added to the
168@@ -309,6 +325,11 @@
169 BugTaskStatusSearch.INPROGRESS,
170 BugTaskStatusSearch.FIXCOMMITTED)
171
172+DEFAULT_SEARCH_BUGTASK_STATUSES_FOR_DISPLAY = [
173+ BugTaskStatusSearchDisplay.items.mapping[item.value]
174+ for item in DEFAULT_SEARCH_BUGTASK_STATUSES
175+ ]
176+
177 class ConjoinedBugTaskEditError(Exception):
178 """An error raised when trying to modify a conjoined bugtask."""
179
180@@ -799,6 +820,12 @@
181 required=False)
182 affects_me = Bool(
183 title=_('Show only bugs affecting me'), required=False)
184+ has_branches = Bool(
185+ title=_('Show only bugs with linked branches'), required=False,
186+ default=True)
187+ has_no_branches = Bool(
188+ title=_('Show only bugs without linked branches'), required=False,
189+ default=True)
190
191
192 class IBugTaskSearch(IBugTaskSearchBase):
193@@ -989,7 +1016,8 @@
194 hardware_owner_is_bug_reporter=None,
195 hardware_owner_is_affected_by_bug=False,
196 hardware_owner_is_subscribed_to_bug=False,
197- hardware_is_linked_to_bug=False
198+ hardware_is_linked_to_bug=False,
199+ linked_branches=None
200 ):
201
202 self.bug = bug
203@@ -1033,6 +1061,7 @@
204 self.hardware_owner_is_subscribed_to_bug = (
205 hardware_owner_is_subscribed_to_bug)
206 self.hardware_is_linked_to_bug = hardware_is_linked_to_bug
207+ self.linked_branches = linked_branches
208
209 def setProduct(self, product):
210 """Set the upstream context on which to filter the search."""
211@@ -1105,7 +1134,7 @@
212 hardware_owner_is_bug_reporter=None,
213 hardware_owner_is_affected_by_bug=False,
214 hardware_owner_is_subscribed_to_bug=False,
215- hardware_is_linked_to_bug=False):
216+ hardware_is_linked_to_bug=False, linked_branches=None):
217 """Create and return a new instance using the parameter list."""
218 search_params = cls(user=user, orderby=order_by)
219
220@@ -1172,6 +1201,7 @@
221 hardware_owner_is_subscribed_to_bug)
222 search_params.hardware_is_linked_to_bug = (
223 hardware_is_linked_to_bug)
224+ search_params.linked_branches=linked_branches
225
226 return search_params
227
228
229=== modified file 'lib/lp/bugs/model/bugtarget.py'
230--- lib/lp/bugs/model/bugtarget.py 2010-01-25 20:04:20 +0000
231+++ lib/lp/bugs/model/bugtarget.py 2010-02-25 08:53:48 +0000
232@@ -57,7 +57,7 @@
233 hardware_owner_is_bug_reporter=None,
234 hardware_owner_is_affected_by_bug=False,
235 hardware_owner_is_subscribed_to_bug=False,
236- hardware_is_linked_to_bug=False):
237+ hardware_is_linked_to_bug=False, linked_branches=None):
238 """See `IHasBugs`."""
239 if status is None:
240 # If no statuses are supplied, default to the
241
242=== modified file 'lib/lp/bugs/model/bugtask.py'
243--- lib/lp/bugs/model/bugtask.py 2010-02-20 13:16:38 +0000
244+++ lib/lp/bugs/model/bugtask.py 2010-02-25 08:53:48 +0000
245@@ -55,13 +55,13 @@
246 from lp.bugs.interfaces.bugattachment import BugAttachmentType
247 from lp.bugs.interfaces.bugnomination import BugNominationStatus
248 from lp.bugs.interfaces.bugtask import (
249- BUG_SUPERVISOR_BUGTASK_STATUSES, BugTaskImportance, BugTaskSearchParams,
250- BugTaskStatus, BugTaskStatusSearch, ConjoinedBugTaskEditError, IBugTask,
251- IBugTaskDelta, IBugTaskSet, IDistroBugTask, IDistroSeriesBugTask,
252- INullBugTask, IProductSeriesBugTask, IUpstreamBugTask, IllegalTarget,
253- RESOLVED_BUGTASK_STATUSES, UNRESOLVED_BUGTASK_STATUSES,
254- UserCannotEditBugTaskImportance, UserCannotEditBugTaskMilestone,
255- UserCannotEditBugTaskStatus)
256+ BUG_SUPERVISOR_BUGTASK_STATUSES, BugBranchSearch, BugTaskImportance,
257+ BugTaskSearchParams, BugTaskStatus, BugTaskStatusSearch,
258+ ConjoinedBugTaskEditError, IBugTask, IBugTaskDelta, IBugTaskSet,
259+ IDistroBugTask, IDistroSeriesBugTask, INullBugTask, IProductSeriesBugTask,
260+ IUpstreamBugTask, IllegalTarget, RESOLVED_BUGTASK_STATUSES,
261+ UNRESOLVED_BUGTASK_STATUSES, UserCannotEditBugTaskImportance,
262+ UserCannotEditBugTaskMilestone, UserCannotEditBugTaskStatus)
263 from lp.bugs.model.bugsubscription import BugSubscription
264 from lp.registry.interfaces.distribution import (
265 IDistribution, IDistributionSet)
266@@ -1671,6 +1671,21 @@
267 if hw_clause is not None:
268 extra_clauses.append(hw_clause)
269
270+ if params.linked_branches == BugBranchSearch.BUGS_WITH_BRANCHES:
271+ extra_clauses.append(
272+ """EXISTS (
273+ SELECT id FROM BugBranch WHERE BugBranch.bug=Bug.id)
274+ """)
275+ elif params.linked_branches == BugBranchSearch.BUGS_WITHOUT_BRANCHES:
276+ extra_clauses.append(
277+ """NOT EXISTS (
278+ SELECT id FROM BugBranch WHERE BugBranch.bug=Bug.id)
279+ """)
280+ else:
281+ # If no branch specific search restriction is specified,
282+ # we don't need to add any clause.
283+ pass
284+
285 orderby_arg = self._processOrderBy(params)
286
287 query = " AND ".join(extra_clauses)
288
289=== added file 'lib/lp/bugs/stories/bugtask-searches/xx-filter-by-linked-branches.txt'
290--- lib/lp/bugs/stories/bugtask-searches/xx-filter-by-linked-branches.txt 1970-01-01 00:00:00 +0000
291+++ lib/lp/bugs/stories/bugtask-searches/xx-filter-by-linked-branches.txt 2010-02-25 08:53:48 +0000
292@@ -0,0 +1,64 @@
293+= Searching for bugs with linked branches =
294+
295+Using the "advanced search" form, we can limit a bug task search
296+to bugs that are linked to branches or to bugs that are not linked
297+to any branches. Normally, both options are turned on.
298+
299+ >>> anon_browser.open(
300+ ... 'http://bugs.launchpad.dev/firefox/+bugs?advanced=1')
301+ >>> anon_browser.getControl(
302+ ... 'Show only bugs with linked branches').selected
303+ True
304+ >>> anon_browser.getControl(
305+ ... 'Show only bugs without linked branches').selected
306+ True
307+
308+In this case all bugs are returned.
309+
310+ >>> from lp.bugs.tests.bug import print_bugtasks
311+ >>> anon_browser.getControl('Search', index=1).click()
312+ >>> print_bugtasks(anon_browser.contents)
313+ 5 Firefox install instructions should be complete Critical New
314+ 4 Reflow problems with complex page layouts Medium New
315+ 1 Firefox does not support SVG Low New
316+
317+When we uncheck 'Show only bugs without linked branches', only bugs with
318+linkes branches are returned.
319+
320+ >>> anon_browser.open(
321+ ... 'http://bugs.launchpad.dev/firefox/+bugs?advanced=1')
322+ >>> without_branches = anon_browser.getControl(
323+ ... 'Show only bugs without linked branches')
324+ >>> without_branches.selected = False
325+ >>> anon_browser.getControl('Search', index=1).click()
326+ >>> print_bugtasks(anon_browser.contents)
327+ 5 Firefox install instructions should be complete Critical New
328+ 4 Reflow problems with complex page layouts Medium New
329+
330+Similary, we can search for branches that don't have linked branches, if
331+we uncheck 'Show only bugs with linked branches'.
332+
333+ >>> anon_browser.open(
334+ ... 'http://bugs.launchpad.dev/firefox/+bugs?advanced=1')
335+ >>> with_branches = anon_browser.getControl(
336+ ... 'Show only bugs with linked branches')
337+ >>> with_branches.selected = False
338+ >>> anon_browser.getControl('Search', index=1).click()
339+ >>> print_bugtasks(anon_browser.contents)
340+ 1 Firefox does not support SVG Low New
341+
342+If we uncheck both fields, all bugs are returned.
343+
344+ >>> anon_browser.open(
345+ ... 'http://bugs.launchpad.dev/firefox/+bugs?advanced=1')
346+ >>> with_branches = anon_browser.getControl(
347+ ... 'Show only bugs with linked branches')
348+ >>> with_branches.selected = False
349+ >>> without_branches = anon_browser.getControl(
350+ ... 'Show only bugs without linked branches')
351+ >>> without_branches.selected = False
352+ >>> anon_browser.getControl('Search', index=1).click()
353+ >>> print_bugtasks(anon_browser.contents)
354+ 5 Firefox install instructions should be complete Critical New
355+ 4 Reflow problems with complex page layouts Medium New
356+ 1 Firefox does not support SVG Low New
357
358=== modified file 'lib/lp/bugs/templates/bugtask-macros-tableview.pt'
359--- lib/lp/bugs/templates/bugtask-macros-tableview.pt 2010-01-21 16:47:24 +0000
360+++ lib/lp/bugs/templates/bugtask-macros-tableview.pt 2010-02-25 08:53:48 +0000
361@@ -236,7 +236,7 @@
362
363 <metal:advanced_search_form define-macro="advanced_search_form">
364
365- <form class="lesser" name="search" method="get" action="">
366+ <form class="long" name="search" method="get" action="">
367 <span tal:condition="view/current_package|nothing">
368 <input type="hidden" name="field.distribution"
369 tal:attributes="value view/current_package/distribution/name" />
370@@ -260,13 +260,13 @@
371 <div tal:repeat="widget_value view/getStatusWidgetValues">
372 <tal:checkbox
373 define="widget_id string:status.${widget_value/title}">
374-
375 <input name="field.status:list"
376 type="checkbox"
377 tal:attributes="value widget_value/value;
378 checked widget_value/checked;
379 id widget_id"/>
380- <label tal:content="widget_value/title"
381+ <label style="font-weight: normal"
382+ tal:content="widget_value/title"
383 tal:attributes="for widget_id">
384 Unconfirmed
385 </label>
386@@ -285,7 +285,8 @@
387 tal:attributes="value widget_value/value;
388 checked widget_value/checked;
389 id widget_id"/>
390- <label tal:content="widget_value/title"
391+ <label style="font-weight: normal"
392+ tal:content="widget_value/title"
393 tal:attributes="for widget_id">Critical</label>
394
395 </tal:checkbox>
396@@ -315,14 +316,16 @@
397 value="any"
398 id="any"
399 checked="checked" />
400- <label for="any">Doesn&#8217;t matter</label><br />
401+ <label style="font-weight: normal"
402+ for="any">Doesn&#8217;t matter</label><br />
403
404 <input
405 type="radio"
406 name="assignee_option"
407 value="none"
408 id="none" />
409- <label for="none"> Nobody</label><br />
410+ <label style="font-weight: normal"
411+ for="none"> Nobody</label><br />
412 <div class="field"
413 tal:define="error
414 python:view.getFieldError('assignee')">
415@@ -463,10 +466,10 @@
416
417 </fieldset>
418 <fieldset tal:define="show_component_widget view/shouldShowComponentWidget">
419- <legend>Series-specific</legend>
420+ <legend>Milestones, components, and tags</legend>
421 <table>
422 <tr>
423- <td width="40%">
424+ <td>
425 <table tal:define="widget_values view/getMilestoneWidgetValues">
426 <tr>
427 <td><label for="field.milestone">Target milestone:</label></td>
428@@ -481,7 +484,8 @@
429 tal:attributes="value widget_value/value;
430 checked widget_value/checked;
431 id widget_id" />
432- <label tal:content="widget_value/title"
433+ <label style="font-weight: normal"
434+ tal:content="widget_value/title"
435 tal:attributes="for widget_id">
436 dapper
437 </label>
438@@ -493,7 +497,7 @@
439 </tr>
440 </table>
441 </td>
442- <td tal:condition="show_component_widget" width="40%">
443+ <td tal:condition="show_component_widget">
444 <table>
445 <tr>
446 <td><label for="field.component">Component:</label></td>
447@@ -505,57 +509,6 @@
448 </tr>
449 </table>
450 </td>
451- <td>&nbsp;</td>
452- </tr>
453- </table>
454- </fieldset>
455-
456- <fieldset tal:condition="view/shouldShowUpstreamStatusBox">
457- <legend>Upstream status</legend>
458-
459- <table>
460- <tr>
461- <td style="white-space: nowrap"
462- tal:content="structure view/widgets/status_upstream" />
463- </tr>
464- </table>
465-
466- </fieldset>
467-
468- <fieldset>
469- <legend>Other</legend>
470- <table>
471- <tr>
472- <td style="white-space: nowrap">
473- <span tal:content="structure view/widgets/omit_dupes" />
474- <label for="field.omit_dupes">Hide duplicate bugs</label>
475- </td>
476- <td style="white-space: nowrap">
477- <span tal:content="structure view/widgets/has_patch" />
478- <label for="field.has_patch">
479- Show only bugs with patches available
480- </label>
481- </td>
482- </tr>
483- <tr>
484- <td>
485- </td>
486- <td style="white-space: nowrap">
487- <input tal:replace="structure view/widgets/has_cve" />
488- <label tal:attributes="for view/widgets/has_cve/name">
489- Show only bugs associated with a CVE
490- </label>
491- </td>
492- </tr>
493- <tr>
494- <td>
495- </td>
496- <td style="white-space: nowrap">
497- <input tal:replace="structure view/widgets/affects_me" />
498- <label tal:attributes="for view/widgets/affects_me/name">
499- Show only bugs affecting me
500- </label>
501- </td>
502 </tr>
503 <tr>
504 <tal:XXX condition="nothing">
505@@ -567,55 +520,124 @@
506 # FormLayout lands we should be able to use the
507 # standard macro instead.
508 </tal:XXX>
509- <td tal:define="error view/widgets/tag/error">
510+ <td span="2"
511+ tal:define="error view/widgets/tag/error">
512 <div tal:attributes="class python:error and 'error' or ''">
513 <label tal:attributes="for view/widgets/tag/name"
514 tal:content="structure view/widgets/tag/label">
515 Tag
516 </label>: <input tal:replace="structure view/widgets/tag" />
517+ <a href="/+help/tag-search.html"
518+ target="help">Tag search help</a>
519 <div
520 tal:condition="error"
521 class="message"
522 tal:content="structure error"
523 >An error message.</div>
524 </div>
525- <p><a href="/+help/tag-search.html"
526- target="help">Tag search help</a></p>
527- </td>
528- <td>
529+
530 <div condition="view/shouldShowTagsCombinatorWidget"
531 class="value">
532- <label>
533+ <label style="font-weight: normal">
534 <input id="field.tags_combinator.0"
535 name="field.tags_combinator"
536 value="ANY" checked="checked"
537 class="radioType" type="radio" />&nbsp;Any
538 </label>
539 <br />
540- <label>
541+ <label style="font-weight: normal">
542 <input id="field.tags_combinator.1"
543 name="field.tags_combinator"
544 value="ALL"
545 class="radioType" type="radio" />&nbsp;All
546 </label>
547 </div>
548- </td>
549+ </td>
550 </tr>
551+ </table>
552+ </fieldset>
553+
554+ <fieldset tal:condition="view/shouldShowUpstreamStatusBox">
555+ <legend>Upstream status</legend>
556+
557+ <table>
558 <tr>
559- <td tal:condition="view/shouldShowNoPackageWidget">
560- <span tal:content="structure view/widgets/has_no_package" />
561- <label for="field.has_no_package">
562- Hide bugs with packages specified
563- </label>
564- </td>
565- <td style="white-space: nowrap">
566- </td>
567+ <td style="white-space: nowrap"
568+ tal:content="structure view/widgets/status_upstream" />
569 </tr>
570-
571 </table>
572
573 </fieldset>
574- <div><input type="submit" name="search" value="Search" /></div>
575+
576+ <fieldset>
577+ <legend>Bug relationships</legend>
578+ <table>
579+ <tr>
580+ <td style="white-space: nowrap">
581+ <input tal:replace="structure view/widgets/has_cve" />
582+ <label style="font-weight: normal"
583+ tal:attributes="for view/widgets/has_cve/name">
584+ Show only bugs associated with a CVE
585+ </label>
586+ </td>
587+ <td style="white-space: nowrap">
588+ <span tal:content="structure view/widgets/omit_dupes" />
589+ <label style="font-weight: normal"
590+ for="field.omit_dupes">Hide duplicate bugs</label>
591+ </td>
592+ </tr>
593+
594+ <tr>
595+ <td style="white-space: nowrap">
596+ <input tal:replace="structure view/widgets/affects_me" />
597+ <label style="font-weight: normal"
598+ tal:attributes="for view/widgets/affects_me/name">
599+ Show only bugs affecting me
600+ </label>
601+ </td>
602+ <td style="white-space: nowrap"
603+ tal:condition="view/shouldShowNoPackageWidget">
604+ <span tal:content="structure view/widgets/has_no_package" />
605+ <label style="font-weight: normal" for="field.has_no_package">
606+ Hide bugs with packages specified
607+ </label>
608+ </td>
609+ </tr>
610+
611+ <tr>
612+ <td style="white-space: nowrap">
613+ <span tal:content="structure view/widgets/has_patch" />
614+ <label style="font-weight: normal" for="field.has_patch">
615+ Show only bugs with patches available
616+ </label>
617+ </td>
618+ <td>
619+ </td>
620+ </tr>
621+ <tr>
622+ <td style="white-space: nowrap">
623+ <span tal:content="structure view/widgets/has_branches" />
624+ <label style="font-weight: normal" for="field.has_branches">
625+ Show only bugs with linked branches
626+ </label>
627+ </td>
628+ <td>
629+ </td>
630+ </tr>
631+ <tr>
632+ <td style="white-space: nowrap">
633+ <span tal:content="structure view/widgets/has_no_branches" />
634+ <label style="font-weight: normal" for="field.has_no_branches">
635+ Show only bugs without linked branches
636+ </label>
637+ </td>
638+ <td>
639+ </td>
640+ </tr>
641+ </table>
642+
643+ </fieldset>
644+ <div style="margin-top: 1em;"><input type="submit" name="search" value="Search" /></div>
645 </form>
646 </metal:advanced_search_form>
647 </tal:root>

Subscribers

People subscribed via source and target branches

to status/vote changes: