Merge lp://staging/~deryck/launchpad/hot-bugs-list-515232 into lp://staging/launchpad
- hot-bugs-list-515232
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Gavin Panella |
Approved revision: | not available |
Merged at revision: | not available |
Proposed branch: | lp://staging/~deryck/launchpad/hot-bugs-list-515232 |
Merge into: | lp://staging/launchpad |
Diff against target: |
256 lines (+104/-37) 4 files modified
lib/lp/bugs/browser/bugtarget.py (+24/-0) lib/lp/bugs/browser/bugtask.py (+9/-14) lib/lp/bugs/stories/bugs/xx-product-bugs-page.txt (+61/-18) lib/lp/bugs/templates/bugtarget-bugs.pt (+10/-5) |
To merge this branch: | bzr merge lp://staging/~deryck/launchpad/hot-bugs-list-515232 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gavin Panella (community) | Approve | ||
Review via email:
|
Commit message
Create a true hot bugs list for a bugs home page. Also, provide a link to the full list of hot bugs. (The original version of this was backed out for performance reasons.)
Description of the change
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Deryck Hodge (deryck) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Gavin Panella (allenap) wrote : | # |
Hi Deryck,
Woo! This is great :)
There are a few issues that need fixing up I think, but nothing that's
going to pose problems.
Gavin.
> === modified file 'lib/lp/
> --- lib/lp/
> +++ lib/lp/
> @@ -40,6 +40,7 @@
> from canonical.config import config
> from lp.bugs.
> from lp.bugs.
> +from lp.bugs.
> from canonical.
> BugFeedLink, BugTargetLatest
> PersonLatestBug
> @@ -55,6 +56,7 @@
> from canonical.
> from canonical.
> ITemporaryStora
> +from canonical.
> from canonical.
> from canonical.
> from canonical.
> @@ -1264,6 +1266,28 @@
> else:
> return 'None specified'
>
> + @property
> + def hot_bugs(self):
It's not returning a straight list of hot bugs, so consider renaming
this to hot_bugtasks_info or something like that?
> + """Return a dict of the 10 hottest tasks and a has_more_bugs flag."""
> + has_more_bugs = False
> + params = BugTaskSearchPa
> + orderby='-heat', omit_dupes=True,
> + user=self.user, status=
> + # Use 4x as many tasks as bugs that are needed to improve performance.
> + bugtasks = self.context.
> + hot_bugs = []
This will contain bugtasks, so maybe rename it?
> + count = 0
len(hot_bugs) should contain the same number, and is authoritative, so
consider dropping count.
> + for task in bugtasks:
> + # Ensure we only represent a bug once in the list.
> + if task.bug not in [hot_task.bug for hot_task in hot_bugs]:
YOU'RE BURNING MY EYES!
:)
Actually, seeing as it's never going to create a temporary list of
more than 10 bugtasks, I guess it's not crazy. Still, to code
defensively, I think it would be better to accumulate the bugtask's
bugs in a set, and use that to test for membership.
> + if count < 10:
> + hot_bugs.
> + count += 1
> + else:
> + has_more_bugs = True
> + break
> + return {'has_more_bugs': has_more_bugs, 'bugtasks': hot_bugs}
> +
>
> class BugTargetBugTag
> """Helper methods for rendering the bug tags portlet."""
>
> === modified file 'lib/lp/
> --- lib/lp/
> +++ lib/lp/
> @@ -2206,9 +2206,13 @@
> distrosourcepac
> return ["id", "summary", "importance", "status",...
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Deryck Hodge (deryck) wrote : | # |
Hi, Gavin.
Thanks for the review! I knew I was doing some dumb things in there, but I was feeling a bit too close to it after so many iterations.
You had good recommendations all the way around, which I've implemented, except for a couple of them. I didn't change the test -- yes, it's fragile, but the whole point of the page test is to show the ordering of bugs by heat. Also, I needed at least status in the monster-long query to "show all bugs." I trimmed what I could, but it's still a bit long.
Otherwise, I think I took care of all your points.
Cheers,
deryck
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Gavin Panella (allenap) : | # |
Preview Diff
1 | === modified file 'lib/lp/bugs/browser/bugtarget.py' | |||
2 | --- lib/lp/bugs/browser/bugtarget.py 2010-02-10 23:14:56 +0000 | |||
3 | +++ lib/lp/bugs/browser/bugtarget.py 2010-02-12 12:39:21 +0000 | |||
4 | @@ -40,6 +40,7 @@ | |||
5 | 40 | from canonical.config import config | 40 | from canonical.config import config |
6 | 41 | from lp.bugs.browser.bugtask import BugTaskSearchListingView | 41 | from lp.bugs.browser.bugtask import BugTaskSearchListingView |
7 | 42 | from lp.bugs.interfaces.bug import IBug | 42 | from lp.bugs.interfaces.bug import IBug |
8 | 43 | from lp.bugs.interfaces.bugtask import BugTaskSearchParams | ||
9 | 43 | from canonical.launchpad.browser.feeds import ( | 44 | from canonical.launchpad.browser.feeds import ( |
10 | 44 | BugFeedLink, BugTargetLatestBugsFeedLink, FeedsMixin, | 45 | BugFeedLink, BugTargetLatestBugsFeedLink, FeedsMixin, |
11 | 45 | PersonLatestBugsFeedLink) | 46 | PersonLatestBugsFeedLink) |
12 | @@ -55,6 +56,7 @@ | |||
13 | 55 | from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities | 56 | from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities |
14 | 56 | from canonical.launchpad.interfaces.temporaryblobstorage import ( | 57 | from canonical.launchpad.interfaces.temporaryblobstorage import ( |
15 | 57 | ITemporaryStorageManager) | 58 | ITemporaryStorageManager) |
16 | 59 | from canonical.launchpad.searchbuilder import any | ||
17 | 58 | from canonical.launchpad.webapp import urlappend | 60 | from canonical.launchpad.webapp import urlappend |
18 | 59 | from canonical.launchpad.webapp.breadcrumb import Breadcrumb | 61 | from canonical.launchpad.webapp.breadcrumb import Breadcrumb |
19 | 60 | from canonical.launchpad.webapp.interfaces import ILaunchBag, NotFoundError | 62 | from canonical.launchpad.webapp.interfaces import ILaunchBag, NotFoundError |
20 | @@ -1266,6 +1268,28 @@ | |||
21 | 1266 | else: | 1268 | else: |
22 | 1267 | return 'None specified' | 1269 | return 'None specified' |
23 | 1268 | 1270 | ||
24 | 1271 | @cachedproperty | ||
25 | 1272 | def hot_bugs_info(self): | ||
26 | 1273 | """Return a dict of the 10 hottest tasks and a has_more_bugs flag.""" | ||
27 | 1274 | has_more_bugs = False | ||
28 | 1275 | params = BugTaskSearchParams( | ||
29 | 1276 | orderby='-heat', omit_dupes=True, | ||
30 | 1277 | user=self.user, status=any(*UNRESOLVED_BUGTASK_STATUSES)) | ||
31 | 1278 | # Use 4x as many tasks as bugs that are needed to improve performance. | ||
32 | 1279 | bugtasks = self.context.searchTasks(params)[:40] | ||
33 | 1280 | hot_bugtasks = [] | ||
34 | 1281 | hot_bugs = [] | ||
35 | 1282 | for task in bugtasks: | ||
36 | 1283 | # Use hot_bugs list to ensure a bug is only listed once. | ||
37 | 1284 | if task.bug not in hot_bugs: | ||
38 | 1285 | if len(hot_bugtasks) < 10: | ||
39 | 1286 | hot_bugtasks.append(task) | ||
40 | 1287 | hot_bugs.append(task.bug) | ||
41 | 1288 | else: | ||
42 | 1289 | has_more_bugs = True | ||
43 | 1290 | break | ||
44 | 1291 | return {'has_more_bugs': has_more_bugs, 'bugtasks': hot_bugtasks} | ||
45 | 1292 | |||
46 | 1269 | 1293 | ||
47 | 1270 | class BugTargetBugTagsView(LaunchpadView): | 1294 | class BugTargetBugTagsView(LaunchpadView): |
48 | 1271 | """Helper methods for rendering the bug tags portlet.""" | 1295 | """Helper methods for rendering the bug tags portlet.""" |
49 | 1272 | 1296 | ||
50 | === modified file 'lib/lp/bugs/browser/bugtask.py' | |||
51 | --- lib/lp/bugs/browser/bugtask.py 2010-01-26 14:22:41 +0000 | |||
52 | +++ lib/lp/bugs/browser/bugtask.py 2010-02-12 12:39:21 +0000 | |||
53 | @@ -2206,9 +2206,13 @@ | |||
54 | 2206 | distrosourcepackage_context or sourcepackage_context): | 2206 | distrosourcepackage_context or sourcepackage_context): |
55 | 2207 | return ["id", "summary", "importance", "status", "heat"] | 2207 | return ["id", "summary", "importance", "status", "heat"] |
56 | 2208 | elif distribution_context or distroseries_context: | 2208 | elif distribution_context or distroseries_context: |
58 | 2209 | return ["id", "summary", "packagename", "importance", "status", "heat"] | 2209 | return [ |
59 | 2210 | "id", "summary", "packagename", "importance", "status", | ||
60 | 2211 | "heat"] | ||
61 | 2210 | elif project_context: | 2212 | elif project_context: |
63 | 2211 | return ["id", "summary", "productname", "importance", "status", "heat"] | 2213 | return [ |
64 | 2214 | "id", "summary", "productname", "importance", "status", | ||
65 | 2215 | "heat"] | ||
66 | 2212 | else: | 2216 | else: |
67 | 2213 | raise AssertionError( | 2217 | raise AssertionError( |
68 | 2214 | "Unrecognized context; don't know which report " | 2218 | "Unrecognized context; don't know which report " |
69 | @@ -2739,15 +2743,6 @@ | |||
70 | 2739 | return IDistributionSourcePackage(self.context, None) | 2743 | return IDistributionSourcePackage(self.context, None) |
71 | 2740 | 2744 | ||
72 | 2741 | @property | 2745 | @property |
73 | 2742 | def hot_bugtasks(self): | ||
74 | 2743 | """Return the 10 most recently updated bugtasks for this target.""" | ||
75 | 2744 | params = BugTaskSearchParams( | ||
76 | 2745 | orderby="-date_last_updated", omit_dupes=True, user=self.user, | ||
77 | 2746 | status=any(*UNRESOLVED_BUGTASK_STATUSES)) | ||
78 | 2747 | search = self.context.searchTasks(params) | ||
79 | 2748 | return list(search[:10]) | ||
80 | 2749 | |||
81 | 2750 | @property | ||
82 | 2751 | def addquestion_url(self): | 2746 | def addquestion_url(self): |
83 | 2752 | """Return the URL for the +addquestion view for the context.""" | 2747 | """Return the URL for the +addquestion view for the context.""" |
84 | 2753 | if IQuestionTarget.providedBy(self.context): | 2748 | if IQuestionTarget.providedBy(self.context): |
85 | @@ -2803,8 +2798,7 @@ | |||
86 | 2803 | if bug_listing_item.review_action_widget is not None] | 2798 | if bug_listing_item.review_action_widget is not None] |
87 | 2804 | self.widgets = formlib.form.Widgets(widgets_list, len(self.prefix)+1) | 2799 | self.widgets = formlib.form.Widgets(widgets_list, len(self.prefix)+1) |
88 | 2805 | 2800 | ||
91 | 2806 | @action('Save changes', name='submit', | 2801 | @action('Save changes', name='submit', condition=canApproveNominations) |
90 | 2807 | condition=canApproveNominations) | ||
92 | 2808 | def submit_action(self, action, data): | 2802 | def submit_action(self, action, data): |
93 | 2809 | """Accept/Decline bug nominations.""" | 2803 | """Accept/Decline bug nominations.""" |
94 | 2810 | accepted = declined = 0 | 2804 | accepted = declined = 0 |
95 | @@ -3592,7 +3586,8 @@ | |||
96 | 3592 | """Show the columns that summarise expirable bugs.""" | 3586 | """Show the columns that summarise expirable bugs.""" |
97 | 3593 | if (IDistribution.providedBy(self.context) | 3587 | if (IDistribution.providedBy(self.context) |
98 | 3594 | or IDistroSeries.providedBy(self.context)): | 3588 | or IDistroSeries.providedBy(self.context)): |
100 | 3595 | return ['id', 'summary', 'packagename', 'date_last_updated', 'heat'] | 3589 | return [ |
101 | 3590 | 'id', 'summary', 'packagename', 'date_last_updated', 'heat'] | ||
102 | 3596 | else: | 3591 | else: |
103 | 3597 | return ['id', 'summary', 'date_last_updated', 'heat'] | 3592 | return ['id', 'summary', 'date_last_updated', 'heat'] |
104 | 3598 | 3593 | ||
105 | 3599 | 3594 | ||
106 | === modified file 'lib/lp/bugs/stories/bugs/xx-product-bugs-page.txt' | |||
107 | --- lib/lp/bugs/stories/bugs/xx-product-bugs-page.txt 2010-01-26 14:22:41 +0000 | |||
108 | +++ lib/lp/bugs/stories/bugs/xx-product-bugs-page.txt 2010-02-12 12:39:21 +0000 | |||
109 | @@ -131,38 +131,81 @@ | |||
110 | 131 | 131 | ||
111 | 132 | == Hot Bugs == | 132 | == Hot Bugs == |
112 | 133 | 133 | ||
115 | 134 | A listing of the 10 'hottest' bugs (currently simply the bugs most | 134 | A listing of the 10 'hottest' bugs is displayed to allow a quick |
116 | 135 | recently touched) is displayed to allow a quick overview of the project. | 135 | overview of the project. |
117 | 136 | |||
118 | 137 | To demonstrate this, we create 10 bugs and adjust their heat values manually. | ||
119 | 138 | |||
120 | 139 | >>> from zope.component import getUtility | ||
121 | 140 | >>> from canonical.launchpad.ftests import login, logout | ||
122 | 141 | >>> from lp.registry.interfaces.product import IProductSet | ||
123 | 142 | >>> import transaction | ||
124 | 143 | >>> login('foo.bar@canonical.com') | ||
125 | 144 | >>> firefox = getUtility(IProductSet).getByName("firefox") | ||
126 | 145 | >>> heat_values = [0, 400, 200, 600, 100, 50, 50, 50, 50, 50, 50, 50] | ||
127 | 146 | >>> for count in range(1, 11): | ||
128 | 147 | ... summary = 'Summary for new bug %d' % count | ||
129 | 148 | ... bug = factory.makeBug(title=summary, product=firefox) | ||
130 | 149 | ... bug.setHeat(heat_values[count]) | ||
131 | 150 | >>> transaction.commit() | ||
132 | 151 | >>> logout() | ||
133 | 152 | |||
134 | 136 | For each bug we have the number, title, status, importance and the time | 153 | For each bug we have the number, title, status, importance and the time |
135 | 137 | since the last update. | 154 | since the last update. |
136 | 138 | 155 | ||
137 | 139 | >>> anon_browser.open('http://bugs.launchpad.dev/firefox') | 156 | >>> anon_browser.open('http://bugs.launchpad.dev/firefox') |
138 | 140 | >>> print extract_text( | 157 | >>> print extract_text( |
139 | 141 | ... find_tag_by_id(anon_browser.contents, 'hot-bugs')) | 158 | ... find_tag_by_id(anon_browser.contents, 'hot-bugs')) |
150 | 142 | Summary Status Importance Last changed | 159 | Summary Status Importance Last changed |
151 | 143 | #5 Firefox install... New Critical on 2006-07-14 | 160 | #18 Summary for new bug 3 New Undecided ... |
152 | 144 | #4 Reflow problems... New Medium on 2006-07-14 | 161 | #16 Summary for new bug 1 New Undecided ... |
153 | 145 | #1 Firefox does no... New Low on 2006-05-19 | 162 | #17 Summary for new bug 2 New Undecided ... |
154 | 146 | 163 | #19 Summary for new bug 4 New Undecided ... | |
155 | 147 | 164 | #20 Summary for new bug 5 New Undecided ... | |
156 | 148 | Fix released bugs are not shown. We demonstrate this by setting the bugtask | 165 | #21 Summary for new bug 6 New Undecided ... |
157 | 149 | for bug 4 to be "Fix released". | 166 | #22 Summary for new bug 7 New Undecided ... |
158 | 150 | 167 | #23 Summary for new bug 8 New Undecided ... | |
159 | 151 | >>> from zope.component import getUtility | 168 | #24 Summary for new bug 9 New Undecided ... |
160 | 169 | #25 Summary for new bug 10 New Undecided ... | ||
161 | 170 | |||
162 | 171 | |||
163 | 172 | Fix Released bugs are not shown. We demonstrate this by setting the bugtask | ||
164 | 173 | for bug 18 to be "Fix Released". | ||
165 | 174 | |||
166 | 152 | >>> from lp.bugs.interfaces.bug import BugTaskStatus, IBugSet | 175 | >>> from lp.bugs.interfaces.bug import BugTaskStatus, IBugSet |
167 | 153 | >>> from lp.registry.interfaces.person import IPersonSet | 176 | >>> from lp.registry.interfaces.person import IPersonSet |
168 | 154 | >>> login('foo.bar@canonical.com') | 177 | >>> login('foo.bar@canonical.com') |
170 | 155 | >>> bug_4 = getUtility(IBugSet).get(4) | 178 | >>> bug_18 = getUtility(IBugSet).get(18) |
171 | 156 | >>> project_owner = getUtility(IPersonSet).getByName('name12') | 179 | >>> project_owner = getUtility(IPersonSet).getByName('name12') |
173 | 157 | >>> bug_4.bugtasks[0].transitionToStatus( | 180 | >>> bug_18.bugtasks[0].transitionToStatus( |
174 | 158 | ... BugTaskStatus.FIXRELEASED, project_owner) | 181 | ... BugTaskStatus.FIXRELEASED, project_owner) |
175 | 159 | >>> logout() | 182 | >>> logout() |
176 | 160 | 183 | ||
178 | 161 | And then reloading the page. The Fix released bug, bug 4, is no longer shown. | 184 | And then reloading the page. The Fix Released bug, bug 18, is no longer shown. |
179 | 162 | 185 | ||
180 | 163 | >>> anon_browser.reload() | 186 | >>> anon_browser.reload() |
181 | 164 | >>> print extract_text( | 187 | >>> print extract_text( |
182 | 165 | ... find_tag_by_id(anon_browser.contents, 'hot-bugs')) | 188 | ... find_tag_by_id(anon_browser.contents, 'hot-bugs')) |
186 | 166 | Summary Status Importance Last changed | 189 | Summary Status Importance Last changed |
187 | 167 | #5 Firefox install... New Critical on 2006-07-14 | 190 | #16 Summary for new bug 1 New Undecided ... |
188 | 168 | #1 Firefox does no... New Low on 2006-05-19 | 191 | #17 Summary for new bug 2 New Undecided ... |
189 | 192 | #19 Summary for new bug 4 New Undecided ... | ||
190 | 193 | #20 Summary for new bug 5 New Undecided ... | ||
191 | 194 | #21 Summary for new bug 6 New Undecided ... | ||
192 | 195 | #22 Summary for new bug 7 New Undecided ... | ||
193 | 196 | #23 Summary for new bug 8 New Undecided ... | ||
194 | 197 | #24 Summary for new bug 9 New Undecided ... | ||
195 | 198 | #25 Summary for new bug 10 New Undecided ... | ||
196 | 199 | |||
197 | 200 | There is a link to see all bugs by heat if the project has more | ||
198 | 201 | than 10 hot bugs. | ||
199 | 202 | |||
200 | 203 | >>> find_tag_by_id(anon_browser.contents, 'more-hot-bugs') is None | ||
201 | 204 | False | ||
202 | 205 | |||
203 | 206 | Jokosher does not have more than 10 bugs and does not have a link | ||
204 | 207 | to more hot bugs. | ||
205 | 208 | |||
206 | 209 | >>> anon_browser.open('http://bugs.launchpad.dev/jokosher') | ||
207 | 210 | >>> find_tag_by_id(anon_browser.contents, 'more-hot-bugs') is None | ||
208 | 211 | True | ||
209 | 169 | 212 | ||
210 | === modified file 'lib/lp/bugs/templates/bugtarget-bugs.pt' | |||
211 | --- lib/lp/bugs/templates/bugtarget-bugs.pt 2010-01-26 14:22:41 +0000 | |||
212 | +++ lib/lp/bugs/templates/bugtarget-bugs.pt 2010-02-12 12:39:21 +0000 | |||
213 | @@ -10,8 +10,9 @@ | |||
214 | 10 | i18n:domain="malone" | 10 | i18n:domain="malone" |
215 | 11 | > | 11 | > |
216 | 12 | <metal:block fill-slot="head_epilogue"> | 12 | <metal:block fill-slot="head_epilogue"> |
219 | 13 | <script type="text/javascript" src="/+icing/FormatAndColor.js"></script> | 13 | <style type="text/css"> |
220 | 14 | <script type="text/javascript" src="/+icing/PlotKit_Packed.js"></script> | 14 | p#more-hot-bugs {float:right; margin-top:7px;} |
221 | 15 | </style> | ||
222 | 15 | </metal:block> | 16 | </metal:block> |
223 | 16 | <body> | 17 | <body> |
224 | 17 | <tal:side metal:fill-slot="side" condition="view/uses_launchpad_bugtracker"> | 18 | <tal:side metal:fill-slot="side" condition="view/uses_launchpad_bugtracker"> |
225 | @@ -95,7 +96,7 @@ | |||
226 | 95 | </ul> | 96 | </ul> |
227 | 96 | </div> | 97 | </div> |
228 | 97 | 98 | ||
230 | 98 | <tal:has_hot_bugs condition="view/hot_bugtasks"> | 99 | <tal:has_hot_bugs condition="view/hot_bugs_info/bugtasks"> |
231 | 99 | <div class="search-box"> | 100 | <div class="search-box"> |
232 | 100 | <metal:search | 101 | <metal:search |
233 | 101 | use-macro="context/@@+bugtarget-macros-search/simple-search-form" | 102 | use-macro="context/@@+bugtarget-macros-search/simple-search-form" |
234 | @@ -123,7 +124,7 @@ | |||
235 | 123 | </tr> | 124 | </tr> |
236 | 124 | </thead> | 125 | </thead> |
237 | 125 | <tbody> | 126 | <tbody> |
239 | 126 | <tr tal:repeat="bugtask view/hot_bugtasks"> | 127 | <tr tal:repeat="bugtask view/hot_bugs_info/bugtasks"> |
240 | 127 | <td class="icon left"> | 128 | <td class="icon left"> |
241 | 128 | <span tal:replace="structure bugtask/image:icon" /> | 129 | <span tal:replace="structure bugtask/image:icon" /> |
242 | 129 | </td> | 130 | </td> |
243 | @@ -146,9 +147,13 @@ | |||
244 | 146 | </tr> | 147 | </tr> |
245 | 147 | </tbody> | 148 | </tbody> |
246 | 148 | </table> | 149 | </table> |
247 | 150 | <p id="more-hot-bugs" | ||
248 | 151 | tal:condition="view/hot_bugs_info/has_more_bugs"> | ||
249 | 152 | <a tal:attributes="href string:${context/fmt:url/+bugs}?orderby=-heat&field.status%3Alist=NEW&field.status%3Alist=INCOMPLETE_WITH_RESPONSE&field.status%3Alist=INCOMPLETE_WITHOUT_RESPONSE&field.status%3Alist=CONFIRMED&field.status%3Alist=TRIAGED&field.status%3Alist=INPROGRESS&field.status%3Alist=FIXCOMMITTED&field.omit_dupes=on">See all hot bugs</a> | ||
250 | 153 | </p> | ||
251 | 149 | </tal:has_hot_bugs> | 154 | </tal:has_hot_bugs> |
252 | 150 | 155 | ||
254 | 151 | <tal:no_hot_bugs condition="not: view/hot_bugtasks"> | 156 | <tal:no_hot_bugs condition="not: view/hot_bugs_info/bugtasks"> |
255 | 152 | <p id="no-bugs-filed"><strong>There are currently no bugs filed against | 157 | <p id="no-bugs-filed"><strong>There are currently no bugs filed against |
256 | 153 | <tal:project_title replace="context/title" />.</strong></p> | 158 | <tal:project_title replace="context/title" />.</strong></p> |
257 | 154 | 159 |
This branch converts a bugtask.py's hot_bugtasks method to a hot_bugs
method on a bug target. The effect of this change is that the bugs home
page for a project will no longer feature the most recently changed
bugs. The home page will now show the top 10 hottest bugs.
This also fixes bug 442170, bug 77701, and bug 515232.
== Implementation details ==
One version of this landed during week 3 last cycle, but the branch was
reverted last minute due to timeout issues. After much playing on
staging with queries (and after talking with Björn), I feel confident
setting a limit and not doing a secondary sort on -datecreated will fix
the timeouts we had.
I also took the opportunity to clean up some lint and add a link to the
rest of the hot bugs list. Because I added this link, I needed a way to
check that more than 10 hot bugs exist. I made the hot_bugs list a dict
with a flag for has_more_bugs, which allows doing this in one method,
too, avoiding having to look up the hot bugs list again.
== Tests ==
Test with:
./bin/test -cvvt xx-product- bugs-page. txt
== Demo and Q/A ==
To QA, visit any bugs home page (e.g. /bugs.launchpad .net/malone/) and confirm that the 10 bugs shown
https:/
are the top ten when you follow the link to the full hot bugs list.
= Launchpad lint =
Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.
Linting changed files: bugs/browser/ bugtarget. py bugs/browser/ bugtask. py bugs/templates/ bugtarget- bugs.pt bugs/stories/ bugs/xx- product- bugs-page. txt
lib/lp/
lib/lp/
lib/lp/
lib/lp/