Merge lp:~deryck/launchpad/milestone-portlet-links-385719 into lp:launchpad
- milestone-portlet-links-385719
- Merge into devel
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Barry Warsaw | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | not available | ||||
Proposed branch: | lp:~deryck/launchpad/milestone-portlet-links-385719 | ||||
Merge into: | lp:launchpad | ||||
Diff against target: | None lines | ||||
To merge this branch: | bzr merge lp:~deryck/launchpad/milestone-portlet-links-385719 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Brad Crittenden (community) | release-critical | Approve | |
Barry Warsaw (community) | code ui* | Approve | |
Review via email: mp+12092@code.launchpad.net |
Commit message
Description of the change
Deryck Hodge (deryck) wrote : | # |
Barry Warsaw (barry) wrote : | # |
On Sep 18, 2009, at 07:30 PM, Deryck Hodge wrote:
>Deryck Hodge has proposed merging lp:~deryck/launchpad/milestone-portlet-links-385719 into lp:launchpad/devel.
>
>Requested reviews:
> Canonical Launchpad Engineering (launchpad)
>
>= Summary =
>
>Bug #385719 notes that it's not possible to get to a milestone bug
>listing from the bugs home page for a project (or distro either). This
>branch adds a milestone-targeted bugs portlet to a bugs home page for a
>distro or project, as well as for series bug pages.
Nice. I often that with LP2.0 it's very difficult to get to a milestone
without url hacking. So making more links to milestones always makes me
happy. This is a nice branch, and thanks for working on it.
I have only minor style issues with the code, but they should be easy to fix,
so merge-conditional, r=me with their consideration.
review approve code ui*
status approve
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
> @@ -1142,11 +1136,20 @@
> elif IProductSeries(
> serieses = self.context.
> else:
> - raise AssertionError, ("series_bug_counts called with "
> - "illegal context")
> -
> + raise AssertionError, ("series_list called with illegal context")
Better to spell that:
raise AssertionError(
IOW, better to instantiate exceptions explicitly than to let Python do it
implicitly.
> + return serieses
"serieses" - waauugghh! ;)
> +
> + @property
> + def series_
> + """Return a buglisting for each series.
> +
> + The list is sorted newest series to oldest.
> +
> + The count only considers bugs that the user would actually be
> + able to see in a listing.
> + """
> series_buglistings = []
> - for series in serieses:
> + for series in self.series_list:
> series_bug_count = series.
> if series_bug_count > 0:
> series_
> @@ -1157,6 +1160,21 @@
>
> return series_buglistings
>
> + @property
> + def milestone_
> + """Return a buglisting for each milestone."""
> + milestone_
> + for series in self.series_list:
> + for milestone in series.milestones:
> + milestone_bug_count = milestone.
> + if milestone_bug_count > 0:
> + milestone_
> + dict(
> + title=milestone
> + url=canonical_
> + count=milestone
That last line should be
=== added file 'lib/lp/
--- lib/lp/
Brad Crittenden (bac) wrote : | # |
Deryck,
Thanks for the fix. I note the visual confusion caused by the portlet counts not being aligned. Let's remember to fix that soon but not now. Please open a bug.
Deryck Hodge (deryck) wrote : | # |
Bug #434781 is tracking the mis-alignment of numbers in the portlets.
Preview Diff
1 | === modified file 'lib/lp/bugs/browser/bugtarget.py' | |||
2 | --- lib/lp/bugs/browser/bugtarget.py 2009-09-10 12:47:31 +0000 | |||
3 | +++ lib/lp/bugs/browser/bugtarget.py 2009-09-18 19:01:31 +0000 | |||
4 | @@ -279,7 +279,8 @@ | |||
5 | 279 | # The user is trying to file a new Ubuntu bug via the web | 279 | # The user is trying to file a new Ubuntu bug via the web |
6 | 280 | # interface and without using apport. Redirect to a page | 280 | # interface and without using apport. Redirect to a page |
7 | 281 | # explaining the preferred bug-filing procedure. | 281 | # explaining the preferred bug-filing procedure. |
9 | 282 | self.request.response.redirect(config.malone.ubuntu_bug_filing_url) | 282 | self.request.response.redirect( |
10 | 283 | config.malone.ubuntu_bug_filing_url) | ||
11 | 283 | if self.extra_data_token is not None: | 284 | if self.extra_data_token is not None: |
12 | 284 | # self.extra_data has been initialized in publishTraverse(). | 285 | # self.extra_data has been initialized in publishTraverse(). |
13 | 285 | if self.extra_data.initial_summary: | 286 | if self.extra_data.initial_summary: |
14 | @@ -1125,14 +1126,7 @@ | |||
15 | 1125 | """Helper methods for rendering bug listings.""" | 1126 | """Helper methods for rendering bug listings.""" |
16 | 1126 | 1127 | ||
17 | 1127 | @property | 1128 | @property |
26 | 1128 | def series_buglistings(self): | 1129 | def series_list(self): |
19 | 1129 | """Return a buglisting for each series. | ||
20 | 1130 | |||
21 | 1131 | The list is sorted newest series to oldest. | ||
22 | 1132 | |||
23 | 1133 | The count only considers bugs that the user would actually be | ||
24 | 1134 | able to see in a listing. | ||
25 | 1135 | """ | ||
27 | 1136 | if IDistribution(self.context, None): | 1130 | if IDistribution(self.context, None): |
28 | 1137 | serieses = self.context.serieses | 1131 | serieses = self.context.serieses |
29 | 1138 | elif IProduct(self.context, None): | 1132 | elif IProduct(self.context, None): |
30 | @@ -1142,11 +1136,20 @@ | |||
31 | 1142 | elif IProductSeries(self.context, None): | 1136 | elif IProductSeries(self.context, None): |
32 | 1143 | serieses = self.context.product.serieses | 1137 | serieses = self.context.product.serieses |
33 | 1144 | else: | 1138 | else: |
37 | 1145 | raise AssertionError, ("series_bug_counts called with " | 1139 | raise AssertionError, ("series_list called with illegal context") |
38 | 1146 | "illegal context") | 1140 | return serieses |
39 | 1147 | 1141 | ||
40 | 1142 | @property | ||
41 | 1143 | def series_buglistings(self): | ||
42 | 1144 | """Return a buglisting for each series. | ||
43 | 1145 | |||
44 | 1146 | The list is sorted newest series to oldest. | ||
45 | 1147 | |||
46 | 1148 | The count only considers bugs that the user would actually be | ||
47 | 1149 | able to see in a listing. | ||
48 | 1150 | """ | ||
49 | 1148 | series_buglistings = [] | 1151 | series_buglistings = [] |
51 | 1149 | for series in serieses: | 1152 | for series in self.series_list: |
52 | 1150 | series_bug_count = series.open_bugtasks.count() | 1153 | series_bug_count = series.open_bugtasks.count() |
53 | 1151 | if series_bug_count > 0: | 1154 | if series_bug_count > 0: |
54 | 1152 | series_buglistings.append( | 1155 | series_buglistings.append( |
55 | @@ -1157,6 +1160,21 @@ | |||
56 | 1157 | 1160 | ||
57 | 1158 | return series_buglistings | 1161 | return series_buglistings |
58 | 1159 | 1162 | ||
59 | 1163 | @property | ||
60 | 1164 | def milestone_buglistings(self): | ||
61 | 1165 | """Return a buglisting for each milestone.""" | ||
62 | 1166 | milestone_buglistings = [] | ||
63 | 1167 | for series in self.series_list: | ||
64 | 1168 | for milestone in series.milestones: | ||
65 | 1169 | milestone_bug_count = milestone.open_bugtasks.count() | ||
66 | 1170 | if milestone_bug_count > 0: | ||
67 | 1171 | milestone_buglistings.append( | ||
68 | 1172 | dict( | ||
69 | 1173 | title=milestone.name, | ||
70 | 1174 | url=canonical_url(milestone), | ||
71 | 1175 | count=milestone_bug_count)) | ||
72 | 1176 | return milestone_buglistings | ||
73 | 1177 | |||
74 | 1160 | 1178 | ||
75 | 1161 | class BugCountDataItem: | 1179 | class BugCountDataItem: |
76 | 1162 | """Data about bug count for a status.""" | 1180 | """Data about bug count for a status.""" |
77 | 1163 | 1181 | ||
78 | === modified file 'lib/lp/bugs/browser/configure.zcml' | |||
79 | --- lib/lp/bugs/browser/configure.zcml 2009-09-14 12:19:55 +0000 | |||
80 | +++ lib/lp/bugs/browser/configure.zcml 2009-09-18 18:45:18 +0000 | |||
81 | @@ -342,6 +342,13 @@ | |||
82 | 342 | template="../templates/bugtask-portlet-seriesbugs.pt"/> | 342 | template="../templates/bugtask-portlet-seriesbugs.pt"/> |
83 | 343 | <browser:page | 343 | <browser:page |
84 | 344 | for="lp.registry.interfaces.distroseries.IDistroSeries" | 344 | for="lp.registry.interfaces.distroseries.IDistroSeries" |
85 | 345 | class="lp.bugs.browser.bugtarget.BugTargetBugListingView" | ||
86 | 346 | facet="bugs" | ||
87 | 347 | permission="zope.Public" | ||
88 | 348 | name="+portlet-bugtasklist-milestonebugs" | ||
89 | 349 | template="../templates/bugtask-portlet-milestonebugs.pt"/> | ||
90 | 350 | <browser:page | ||
91 | 351 | for="lp.registry.interfaces.distroseries.IDistroSeries" | ||
92 | 345 | name="+nominations" | 352 | name="+nominations" |
93 | 346 | class="lp.bugs.browser.bugtask.BugNominationsView" | 353 | class="lp.bugs.browser.bugtask.BugNominationsView" |
94 | 347 | permission="zope.Public" | 354 | permission="zope.Public" |
95 | @@ -369,6 +376,13 @@ | |||
96 | 369 | name="+portlet-bugtasklist-seriesbugs" | 376 | name="+portlet-bugtasklist-seriesbugs" |
97 | 370 | template="../templates/bugtask-portlet-seriesbugs.pt"/> | 377 | template="../templates/bugtask-portlet-seriesbugs.pt"/> |
98 | 371 | <browser:page | 378 | <browser:page |
99 | 379 | for="lp.registry.interfaces.product.IProduct" | ||
100 | 380 | class="lp.bugs.browser.bugtarget.BugTargetBugListingView" | ||
101 | 381 | facet="bugs" | ||
102 | 382 | permission="zope.Public" | ||
103 | 383 | name="+portlet-bugtasklist-milestonebugs" | ||
104 | 384 | template="../templates/bugtask-portlet-milestonebugs.pt"/> | ||
105 | 385 | <browser:page | ||
106 | 372 | for="lp.registry.interfaces.distribution.IDistribution" | 386 | for="lp.registry.interfaces.distribution.IDistribution" |
107 | 373 | class="lp.bugs.browser.bugtarget.BugTargetBugListingView" | 387 | class="lp.bugs.browser.bugtarget.BugTargetBugListingView" |
108 | 374 | facet="bugs" | 388 | facet="bugs" |
109 | @@ -376,6 +390,13 @@ | |||
110 | 376 | name="+portlet-bugtasklist-seriesbugs" | 390 | name="+portlet-bugtasklist-seriesbugs" |
111 | 377 | template="../templates/bugtask-portlet-seriesbugs.pt"/> | 391 | template="../templates/bugtask-portlet-seriesbugs.pt"/> |
112 | 378 | <browser:page | 392 | <browser:page |
113 | 393 | for="lp.registry.interfaces.distribution.IDistribution" | ||
114 | 394 | class="lp.bugs.browser.bugtarget.BugTargetBugListingView" | ||
115 | 395 | facet="bugs" | ||
116 | 396 | permission="zope.Public" | ||
117 | 397 | name="+portlet-bugtasklist-milestonebugs" | ||
118 | 398 | template="../templates/bugtask-portlet-milestonebugs.pt"/> | ||
119 | 399 | <browser:page | ||
120 | 379 | name="+filebug" | 400 | name="+filebug" |
121 | 380 | for="lp.registry.interfaces.project.IProject" | 401 | for="lp.registry.interfaces.project.IProject" |
122 | 381 | class="lp.bugs.browser.bugtarget.ProjectFileBugGuidedView" | 402 | class="lp.bugs.browser.bugtarget.ProjectFileBugGuidedView" |
123 | @@ -408,6 +429,13 @@ | |||
124 | 408 | template="../templates/bugtask-portlet-seriesbugs.pt"/> | 429 | template="../templates/bugtask-portlet-seriesbugs.pt"/> |
125 | 409 | <browser:page | 430 | <browser:page |
126 | 410 | for="lp.registry.interfaces.productseries.IProductSeries" | 431 | for="lp.registry.interfaces.productseries.IProductSeries" |
127 | 432 | class="lp.bugs.browser.bugtarget.BugTargetBugListingView" | ||
128 | 433 | facet="bugs" | ||
129 | 434 | permission="zope.Public" | ||
130 | 435 | name="+portlet-bugtasklist-milestonebugs" | ||
131 | 436 | template="../templates/bugtask-portlet-milestonebugs.pt"/> | ||
132 | 437 | <browser:page | ||
133 | 438 | for="lp.registry.interfaces.productseries.IProductSeries" | ||
134 | 411 | name="+nominations" | 439 | name="+nominations" |
135 | 412 | class="lp.bugs.browser.bugtask.BugNominationsView" | 440 | class="lp.bugs.browser.bugtask.BugNominationsView" |
136 | 413 | permission="zope.Public" | 441 | permission="zope.Public" |
137 | 414 | 442 | ||
138 | === added file 'lib/lp/bugs/stories/bugs/xx-portlets-bug-milestones.txt' | |||
139 | --- lib/lp/bugs/stories/bugs/xx-portlets-bug-milestones.txt 1970-01-01 00:00:00 +0000 | |||
140 | +++ lib/lp/bugs/stories/bugs/xx-portlets-bug-milestones.txt 2009-09-18 18:41:39 +0000 | |||
141 | @@ -0,0 +1,76 @@ | |||
142 | 1 | Milestone-targeted bugs portlet | ||
143 | 2 | =============================== | ||
144 | 3 | |||
145 | 4 | The milestone-targeted bugs portlet displays the number of bugs that have | ||
146 | 5 | been targeted to a specific milestone. | ||
147 | 6 | |||
148 | 7 | This portlet is available from a distribution's bug page. | ||
149 | 8 | |||
150 | 9 | >>> anon_browser.open("http://bugs.launchpad.dev/debian/+bugs") | ||
151 | 10 | >>> portlet = find_portlet( | ||
152 | 11 | ... anon_browser.contents, "Milestone-targeted bugs") | ||
153 | 12 | >>> print extract_text(portlet) | ||
154 | 13 | Milestone-targeted bugs | ||
155 | 14 | 3.1 1 | ||
156 | 15 | |||
157 | 16 | It is also available from the bug page for a series in the distribution. | ||
158 | 17 | |||
159 | 18 | >>> anon_browser.open("http://bugs.launchpad.dev/debian/sarge/+bugs") | ||
160 | 19 | >>> portlet = find_portlet( | ||
161 | 20 | ... anon_browser.contents, "Milestone-targeted bugs") | ||
162 | 21 | >>> print extract_text(portlet) | ||
163 | 22 | Milestone-targeted bugs | ||
164 | 23 | 3.1 1 | ||
165 | 24 | |||
166 | 25 | The portlet is also available from a project's bugs home page. To demonstrate | ||
167 | 26 | this, a project has to first have one of its milestones associated with a bug. | ||
168 | 27 | If there are no milestones with bugs, then there is no milestone-targeted | ||
169 | 28 | portlet. | ||
170 | 29 | |||
171 | 30 | >>> anon_browser.open("http://bugs.launchpad.dev/firefox") | ||
172 | 31 | >>> portlet = find_portlet( | ||
173 | 32 | ... anon_browser.contents, "Milestone-targeted bugs") | ||
174 | 33 | >>> portlet is None | ||
175 | 34 | True | ||
176 | 35 | |||
177 | 36 | To enable the portlet, a bugtask needs to have a milestone associated with it. | ||
178 | 37 | Bug 4 has a Firefox bugtask, which can be used once a milestone is selected. | ||
179 | 38 | |||
180 | 39 | >>> login('test@canonical.com') | ||
181 | 40 | >>> from zope.component import getUtility | ||
182 | 41 | >>> from lp.bugs.interfaces.bugtask import IBugTaskSet | ||
183 | 42 | >>> ff_bugtask = getUtility(IBugTaskSet).get(13) | ||
184 | 43 | >>> print ff_bugtask.bug.id | ||
185 | 44 | 4 | ||
186 | 45 | |||
187 | 46 | >>> from lp.registry.interfaces.product import IProductSet | ||
188 | 47 | >>> from lp.registry.interfaces.milestone import IMilestoneSet | ||
189 | 48 | >>> firefox = getUtility(IProductSet).getByName('firefox') | ||
190 | 49 | >>> ff_milestone = getUtility(IMilestoneSet).getByNameAndProduct( | ||
191 | 50 | ... "1.0", firefox) | ||
192 | 51 | >>> print ff_milestone.name | ||
193 | 52 | 1.0 | ||
194 | 53 | |||
195 | 54 | The bugtask milestone is set to the Firefox 1.0 milestone. | ||
196 | 55 | |||
197 | 56 | >>> ff_bugtask.milestone = ff_milestone.id | ||
198 | 57 | >>> logout() | ||
199 | 58 | |||
200 | 59 | Now Firefox has a milestone-targeted bugs portlet on the project's bugs home | ||
201 | 60 | page. | ||
202 | 61 | |||
203 | 62 | >>> anon_browser.open("http://bugs.launchpad.dev/firefox") | ||
204 | 63 | >>> portlet = find_portlet( | ||
205 | 64 | ... anon_browser.contents, "Milestone-targeted bugs") | ||
206 | 65 | >>> print extract_text(portlet) | ||
207 | 66 | Milestone-targeted bugs | ||
208 | 67 | 1.0 1 | ||
209 | 68 | |||
210 | 69 | The portlet will also appear on a project's series bug page. | ||
211 | 70 | |||
212 | 71 | >>> anon_browser.open("http://launchpad.dev/firefox/trunk/+bugs") | ||
213 | 72 | >>> portlet = find_portlet( | ||
214 | 73 | ... anon_browser.contents, "Milestone-targeted bugs") | ||
215 | 74 | >>> print extract_text(portlet) | ||
216 | 75 | Milestone-targeted bugs | ||
217 | 76 | 1.0 1 | ||
218 | 0 | 77 | ||
219 | === modified file 'lib/lp/bugs/templates/buglisting-default.pt' | |||
220 | --- lib/lp/bugs/templates/buglisting-default.pt 2009-09-11 16:33:22 +0000 | |||
221 | +++ lib/lp/bugs/templates/buglisting-default.pt 2009-09-16 17:05:13 +0000 | |||
222 | @@ -62,6 +62,9 @@ | |||
223 | 62 | <tal:releasecriticalbugs | 62 | <tal:releasecriticalbugs |
224 | 63 | tal:condition="view/shouldShowReleaseCriticalPortlet" | 63 | tal:condition="view/shouldShowReleaseCriticalPortlet" |
225 | 64 | tal:content="structure context/@@+portlet-bugtasklist-seriesbugs" /> | 64 | tal:content="structure context/@@+portlet-bugtasklist-seriesbugs" /> |
226 | 65 | <tal:milestonecriticalbugs | ||
227 | 66 | tal:condition="view/shouldShowReleaseCriticalPortlet" | ||
228 | 67 | tal:content="structure context/@@+portlet-bugtasklist-milestonebugs" /> | ||
229 | 65 | </tal:do_not_show_portlets_advanced_form> | 68 | </tal:do_not_show_portlets_advanced_form> |
230 | 66 | </tal:side> | 69 | </tal:side> |
231 | 67 | </body> | 70 | </body> |
232 | 68 | 71 | ||
233 | === modified file 'lib/lp/bugs/templates/bugtarget-bugs.pt' | |||
234 | --- lib/lp/bugs/templates/bugtarget-bugs.pt 2009-07-18 00:05:49 +0000 | |||
235 | +++ lib/lp/bugs/templates/bugtarget-bugs.pt 2009-09-16 17:05:13 +0000 | |||
236 | @@ -19,6 +19,9 @@ | |||
237 | 19 | <tal:releasecriticalbugs | 19 | <tal:releasecriticalbugs |
238 | 20 | tal:condition="view/shouldShowReleaseCriticalPortlet" | 20 | tal:condition="view/shouldShowReleaseCriticalPortlet" |
239 | 21 | tal:content="structure context/@@+portlet-bugtasklist-seriesbugs" /> | 21 | tal:content="structure context/@@+portlet-bugtasklist-seriesbugs" /> |
240 | 22 | <tal:milestonecriticalbugs | ||
241 | 23 | tal:condition="view/shouldShowReleaseCriticalPortlet" | ||
242 | 24 | tal:content="structure context/@@+portlet-bugtasklist-milestonebugs" /> | ||
243 | 22 | </metal:portlets> | 25 | </metal:portlets> |
244 | 23 | <body> | 26 | <body> |
245 | 24 | <div metal:fill-slot="main" class="tab-bugs" | 27 | <div metal:fill-slot="main" class="tab-bugs" |
246 | 25 | 28 | ||
247 | === added file 'lib/lp/bugs/templates/bugtask-portlet-milestonebugs.pt' | |||
248 | --- lib/lp/bugs/templates/bugtask-portlet-milestonebugs.pt 1970-01-01 00:00:00 +0000 | |||
249 | +++ lib/lp/bugs/templates/bugtask-portlet-milestonebugs.pt 2009-09-16 17:05:13 +0000 | |||
250 | @@ -0,0 +1,24 @@ | |||
251 | 1 | <div | ||
252 | 2 | xmlns:tal="http://xml.zope.org/namespaces/tal" | ||
253 | 3 | xmlns:metal="http://xml.zope.org/namespaces/metal" | ||
254 | 4 | xmlns:i18n="http://xml.zope.org/namespaces/i18n" | ||
255 | 5 | class="portlet" id="portlet-milestone-critical-bugs" | ||
256 | 6 | tal:define="milestone_buglistings view/milestone_buglistings" | ||
257 | 7 | tal:condition="milestone_buglistings"> | ||
258 | 8 | |||
259 | 9 | <h2>Milestone-targeted bugs</h2> | ||
260 | 10 | |||
261 | 11 | <div class="portletBody"> | ||
262 | 12 | <table width="100%"> | ||
263 | 13 | <tr tal:repeat="milestone_openbugs milestone_buglistings"> | ||
264 | 14 | <td> | ||
265 | 15 | <a href="" | ||
266 | 16 | tal:content="milestone_openbugs/title" | ||
267 | 17 | tal:attributes="href milestone_openbugs/url">sid</a> | ||
268 | 18 | </td> | ||
269 | 19 | <td><span tal:replace="milestone_openbugs/count">2</span></td> | ||
270 | 20 | </tr> | ||
271 | 21 | </table> | ||
272 | 22 | </div> | ||
273 | 23 | |||
274 | 24 | </div> |
= Summary =
Bug #385719 notes that it's not possible to get to a milestone bug
listing from the bugs home page for a project (or distro either). This
branch adds a milestone-targeted bugs portlet to a bugs home page for a
distro or project, as well as for series bug pages.
= Implementation =
This code pretty much copies the work that creates the series-targeted
bugs portlet. I did change the view class slightly to break out the
bits that get a list of series, since the function for getting
milestones also needs this series list.
I added a page test to cover the new functionality.
== Tests ==
./bin/test -vv -t xx-portlets- bug-milestones. txt
== Demo and Q/A ==
To demo, use the dev server and hit: /bugs.launchpad .dev/debian/ +bugs
https:/
There should be a portlet for the milestone links there.
To QA, visit any project bugs home that use milestones and verify there /bugs.launchpad .net/malone/
is a portlet on the bugs home. https:/
should have a milestone portlet linking the 3.0 and 2.2.8 milestones.
= Launchpad lint =
Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.
Linting changed files: bugs/templates/ bugtask- portlet- milestonebugs. pt bugs/browser/ bugtarget. py bugs/stories/ bugs/xx- portlets- bug-milestones. txt bugs/browser/ configure. zcml bugs/templates/ buglisting- default. pt bugs/templates/ bugtarget- bugs.pt
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/