Merge lp:~adeuring/launchpad/bug-201015-bug-branch-search into lp:launchpad/db-devel
- bug-201015-bug-branch-search
- Merge into db-devel
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Curtis Hovey (community) | Approve | ||
Review via email: mp+19699@code.launchpad.net |
Commit message
Description of the change
Abel Deuring (adeuring) wrote : | # |
Curtis Hovey (sinzui) wrote : | # |
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://
http://
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 {
}
.long fieldset {
}
.long legend {
color: #666;
}
* In bugtask-
<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
...
Abel Deuring (adeuring) wrote : | # |
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://
> http://
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-
> <metal:
> <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...
Abel Deuring (adeuring) wrote : | # |
A screenshot of the the searhc page: http://
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://
Preview Diff
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’t matter</label><br /> |
401 | + <label style="font-weight: normal" |
402 | + for="any">Doesn’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> </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" /> 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" /> 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> |
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 searchTasks( )) for the new search option
- 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.
- 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 by-linked- branches. txt
./bin/test -t xx-filter-
no lint