Merge lp:~gary/launchpad/bug724025 into lp:launchpad
- bug724025
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Graham Binns |
Approved revision: | no longer in the source branch. |
Merged at revision: | 13772 |
Proposed branch: | lp:~gary/launchpad/bug724025 |
Merge into: | lp:launchpad |
Diff against target: |
522 lines (+144/-162) 5 files modified
lib/lp/bugs/browser/bugtask.py (+72/-81) lib/lp/bugs/browser/configure.zcml (+1/-2) lib/lp/bugs/templates/bugtask-tasks-and-nominations-table-row.pt (+66/-74) setup.py (+1/-2) versions.cfg (+4/-3) |
To merge this branch: | bzr merge lp:~gary/launchpad/bug724025 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Graham Binns (community) | code | Approve | |
Review via email: mp+72484@code.launchpad.net |
Commit message
[incr] [r=gmb][bug=724025] Speed up an inner loop for BugTask:+index with many tasks.
Description of the change
This branch takes the previous work to reduce the Python cost of many tasks on the BugTask:+index page and extends it a bit more. This time, we optimize the inner loop of rendering many tasks by calculating the shared data for the view carefully at initialization, and by using a Chameleon template for the rendering.
Note that this code has *no* SQL queries while the inner loop is run, thanks to previous work by Robert. This is entirely rendering time.
The initialization saves a bit less than half a second on my system with 160/320 bugtasks (the doubled number represents the parent bugtask for a sourcepackage). Hopefully it is fairly straightforward to read: I collect the data, and then the template is simplified a bit.
The switch to Chameleon is even less to read. It also saves around half a second in the conditions I described above. You might know that I disabled Chameleon earlier for ++profile++. The new version does not write compiled files to disk by default. While I would prefer it to do this in the future, it is simpler to do what I have done here. The first time BugTask:+index is rendered, a bit of time will be spent to calculate the bytecode for the template; subsequently, the cost will be gone until the process restarts.
There are no tests, because it is existing functionality, and we already were not generating SQL in the inner loop.
Lint is happy.
To QA, go to any BugTask:+index page. The first time a +index page is rendered for that process, it will be a bit slower, as described above. Subsequently, you should have a modest speed gain.
This bug will get one or two more changes before I move on. Minimally, I plan to make only the first 50 bugtasks render initially, with the current context bugtask at the top, and then JS to render the remaining tasks on demand. Ideally, I'll also address an unrelated aspect of why this page is slow: we need to pre-load associated branches, using code that Danilo worked on in another branch.
Thank you
Graham Binns (gmb) : | # |
Gary Poster (gary) wrote : | # |
Preview Diff
1 | === modified file 'lib/lp/bugs/browser/bugtask.py' | |||
2 | --- lib/lp/bugs/browser/bugtask.py 2011-08-22 13:13:28 +0000 | |||
3 | +++ lib/lp/bugs/browser/bugtask.py 2011-08-23 01:53:28 +0000 | |||
4 | @@ -75,7 +75,7 @@ | |||
5 | 75 | from lazr.uri import URI | 75 | from lazr.uri import URI |
6 | 76 | from pytz import utc | 76 | from pytz import utc |
7 | 77 | from simplejson import dumps | 77 | from simplejson import dumps |
9 | 78 | from z3c.ptcompat import ViewPageTemplateFile | 78 | from z3c.pt.pagetemplate import ViewPageTemplateFile |
10 | 79 | from zope import ( | 79 | from zope import ( |
11 | 80 | component, | 80 | component, |
12 | 81 | formlib, | 81 | formlib, |
13 | @@ -1067,7 +1067,7 @@ | |||
14 | 1067 | class BugTaskBugWatchMixin: | 1067 | class BugTaskBugWatchMixin: |
15 | 1068 | """A mixin to be used where a BugTask view displays BugWatch data.""" | 1068 | """A mixin to be used where a BugTask view displays BugWatch data.""" |
16 | 1069 | 1069 | ||
18 | 1070 | @property | 1070 | @cachedproperty |
19 | 1071 | def bug_watch_error_message(self): | 1071 | def bug_watch_error_message(self): |
20 | 1072 | """Return a browser-useable error message for a bug watch.""" | 1072 | """Return a browser-useable error message for a bug watch.""" |
21 | 1073 | if not self.context.bugwatch: | 1073 | if not self.context.bugwatch: |
22 | @@ -3383,10 +3383,50 @@ | |||
23 | 3383 | target_link_title = None | 3383 | target_link_title = None |
24 | 3384 | many_bugtasks = False | 3384 | many_bugtasks = False |
25 | 3385 | 3385 | ||
26 | 3386 | template = ViewPageTemplateFile( | ||
27 | 3387 | '../templates/bugtask-tasks-and-nominations-table-row.pt') | ||
28 | 3388 | |||
29 | 3386 | def __init__(self, context, request): | 3389 | def __init__(self, context, request): |
30 | 3387 | super(BugTaskTableRowView, self).__init__(context, request) | 3390 | super(BugTaskTableRowView, self).__init__(context, request) |
31 | 3388 | self.milestone_source = MilestoneVocabulary | 3391 | self.milestone_source = MilestoneVocabulary |
32 | 3389 | 3392 | ||
33 | 3393 | def initialize(self): | ||
34 | 3394 | super(BugTaskTableRowView, self).initialize() | ||
35 | 3395 | link = canonical_url(self.context) | ||
36 | 3396 | edit_link = link + '/+editstatus' | ||
37 | 3397 | view_link = link + '/+viewstatus' | ||
38 | 3398 | can_edit = check_permission('launchpad.Edit', self.context) | ||
39 | 3399 | task_link = edit_link if can_edit else view_link | ||
40 | 3400 | bugtask_id = self.context.id | ||
41 | 3401 | launchbag = getUtility(ILaunchBag) | ||
42 | 3402 | is_primary = self.context.id == launchbag.bugtask.id | ||
43 | 3403 | self.data = dict( | ||
44 | 3404 | # Looking at many_bugtasks is an important optimization. With | ||
45 | 3405 | # 150+ bugtasks, it can save three or four seconds of rendering | ||
46 | 3406 | # time. | ||
47 | 3407 | expandable=(not self.many_bugtasks and self.canSeeTaskDetails()), | ||
48 | 3408 | indent_task=ISeriesBugTarget.providedBy(self.context.target), | ||
49 | 3409 | is_conjoined_slave=self.is_conjoined_slave, | ||
50 | 3410 | task_link=task_link, | ||
51 | 3411 | edit_link=edit_link, | ||
52 | 3412 | view_link=view_link, | ||
53 | 3413 | can_edit=can_edit, | ||
54 | 3414 | link=link, | ||
55 | 3415 | id=bugtask_id, | ||
56 | 3416 | row_id='tasksummary%d' % bugtask_id, | ||
57 | 3417 | form_row_id='task%d' % bugtask_id, | ||
58 | 3418 | row_css_class='highlight' if is_primary else None, | ||
59 | 3419 | target_link=canonical_url(self.context.target), | ||
60 | 3420 | target_link_title=self.target_link_title, | ||
61 | 3421 | user_can_edit_importance=self.context.userCanEditImportance( | ||
62 | 3422 | self.user), | ||
63 | 3423 | importance_css_class='importance' + self.context.importance.name, | ||
64 | 3424 | importance_title=self.context.importance.title, | ||
65 | 3425 | # We always look up all milestones, so there's no harm | ||
66 | 3426 | # using len on the list here and avoid the COUNT query. | ||
67 | 3427 | target_has_milestones=len(self._visible_milestones) > 0, | ||
68 | 3428 | ) | ||
69 | 3429 | |||
70 | 3390 | def canSeeTaskDetails(self): | 3430 | def canSeeTaskDetails(self): |
71 | 3391 | """Whether someone can see a task's status details. | 3431 | """Whether someone can see a task's status details. |
72 | 3392 | 3432 | ||
73 | @@ -3405,42 +3445,6 @@ | |||
74 | 3405 | self.context.bug.duplicateof is None and | 3445 | self.context.bug.duplicateof is None and |
75 | 3406 | not self.is_converted_to_question) | 3446 | not self.is_converted_to_question) |
76 | 3407 | 3447 | ||
77 | 3408 | def expandable(self): | ||
78 | 3409 | """Can the task's details be expanded? | ||
79 | 3410 | |||
80 | 3411 | They can if there are not too many bugtasks, and if the user can see | ||
81 | 3412 | the task details.""" | ||
82 | 3413 | # Looking at many_bugtasks is an important optimization. With 150+ | ||
83 | 3414 | # bugtasks, it can save three or four seconds of rendering time. | ||
84 | 3415 | return not self.many_bugtasks and self.canSeeTaskDetails() | ||
85 | 3416 | |||
86 | 3417 | def getTaskRowCSSClass(self): | ||
87 | 3418 | """The appropriate CSS class for the row in the Affects table. | ||
88 | 3419 | |||
89 | 3420 | Currently this consists solely of highlighting the current context. | ||
90 | 3421 | """ | ||
91 | 3422 | bugtask = self.context | ||
92 | 3423 | if bugtask == getUtility(ILaunchBag).bugtask: | ||
93 | 3424 | return 'highlight' | ||
94 | 3425 | else: | ||
95 | 3426 | return None | ||
96 | 3427 | |||
97 | 3428 | def shouldIndentTask(self): | ||
98 | 3429 | """Should this task be indented in the task listing on the bug page? | ||
99 | 3430 | |||
100 | 3431 | Returns True or False. | ||
101 | 3432 | """ | ||
102 | 3433 | return ISeriesBugTarget.providedBy(self.context.target) | ||
103 | 3434 | |||
104 | 3435 | def taskLink(self): | ||
105 | 3436 | """Return the proper link to the bugtask whether it's editable.""" | ||
106 | 3437 | user = getUtility(ILaunchBag).user | ||
107 | 3438 | bugtask = self.context | ||
108 | 3439 | if check_permission('launchpad.Edit', user): | ||
109 | 3440 | return canonical_url(bugtask) + "/+editstatus" | ||
110 | 3441 | else: | ||
111 | 3442 | return canonical_url(bugtask) + "/+viewstatus" | ||
112 | 3443 | |||
113 | 3444 | def _getSeriesTargetNameHelper(self, bugtask): | 3448 | def _getSeriesTargetNameHelper(self, bugtask): |
114 | 3445 | """Return the short name of bugtask's targeted series.""" | 3449 | """Return the short name of bugtask's targeted series.""" |
115 | 3446 | series = bugtask.distroseries or bugtask.productseries | 3450 | series = bugtask.distroseries or bugtask.productseries |
116 | @@ -3535,15 +3539,6 @@ | |||
117 | 3535 | 3539 | ||
118 | 3536 | return items | 3540 | return items |
119 | 3537 | 3541 | ||
120 | 3538 | @cachedproperty | ||
121 | 3539 | def target_has_milestones(self): | ||
122 | 3540 | """Are there any milestones we can target? | ||
123 | 3541 | |||
124 | 3542 | We always look up all milestones, so there's no harm | ||
125 | 3543 | using len on the list here and avoid the COUNT query. | ||
126 | 3544 | """ | ||
127 | 3545 | return len(self._visible_milestones) > 0 | ||
128 | 3546 | |||
129 | 3547 | def bugtask_canonical_url(self): | 3542 | def bugtask_canonical_url(self): |
130 | 3548 | """Return the canonical url for the bugtask.""" | 3543 | """Return the canonical url for the bugtask.""" |
131 | 3549 | return canonical_url(self.context) | 3544 | return canonical_url(self.context) |
132 | @@ -3564,7 +3559,7 @@ | |||
133 | 3564 | """ | 3559 | """ |
134 | 3565 | return self.user is not None | 3560 | return self.user is not None |
135 | 3566 | 3561 | ||
137 | 3567 | @property | 3562 | @cachedproperty |
138 | 3568 | def user_can_edit_milestone(self): | 3563 | def user_can_edit_milestone(self): |
139 | 3569 | """Can the user edit the Milestone field? | 3564 | """Can the user edit the Milestone field? |
140 | 3570 | 3565 | ||
141 | @@ -3602,44 +3597,40 @@ | |||
142 | 3602 | 'title': filter.title, | 3597 | 'title': filter.title, |
143 | 3603 | 'description': filter.description, | 3598 | 'description': filter.description, |
144 | 3604 | }) | 3599 | }) |
145 | 3605 | |||
146 | 3606 | # Display the search field only if the user can set any person | 3600 | # Display the search field only if the user can set any person |
147 | 3607 | # or team | 3601 | # or team |
149 | 3608 | user = getUtility(ILaunchBag).user | 3602 | user = self.user |
150 | 3609 | hide_assignee_team_selection = ( | 3603 | hide_assignee_team_selection = ( |
151 | 3610 | not self.context.userCanSetAnyAssignee(user) and | 3604 | not self.context.userCanSetAnyAssignee(user) and |
152 | 3611 | (user is None or user.teams_participated_in.count() == 0)) | 3605 | (user is None or user.teams_participated_in.count() == 0)) |
184 | 3612 | return dumps({ | 3606 | cx = self.context |
185 | 3613 | 'row_id': 'tasksummary%s' % self.context.id, | 3607 | return dumps(dict( |
186 | 3614 | 'bugtask_path': '/'.join( | 3608 | row_id=self.data['row_id'], |
187 | 3615 | [''] + canonical_url(self.context).split('/')[3:]), | 3609 | bugtask_path='/'.join([''] + self.data['link'].split('/')[3:]), |
188 | 3616 | 'prefix': get_prefix(self.context), | 3610 | prefix=get_prefix(cx), |
189 | 3617 | 'assignee_value': self.context.assignee | 3611 | assignee_value=cx.assignee and cx.assignee.name, |
190 | 3618 | and self.context.assignee.name, | 3612 | assignee_is_team=cx.assignee and cx.assignee.is_team, |
191 | 3619 | 'assignee_is_team': self.context.assignee | 3613 | assignee_vocabulary=assignee_vocabulary, |
192 | 3620 | and self.context.assignee.is_team, | 3614 | assignee_vocabulary_filters=filter_details, |
193 | 3621 | 'assignee_vocabulary': assignee_vocabulary, | 3615 | hide_assignee_team_selection=hide_assignee_team_selection, |
194 | 3622 | 'assignee_vocabulary_filters': filter_details, | 3616 | user_can_unassign=cx.userCanUnassign(user), |
195 | 3623 | 'hide_assignee_team_selection': hide_assignee_team_selection, | 3617 | target_is_product=IProduct.providedBy(cx.target), |
196 | 3624 | 'user_can_unassign': self.context.userCanUnassign(user), | 3618 | status_widget_items=self.status_widget_items, |
197 | 3625 | 'target_is_product': IProduct.providedBy(self.context.target), | 3619 | status_value=cx.status.title, |
198 | 3626 | 'status_widget_items': self.status_widget_items, | 3620 | importance_widget_items=self.importance_widget_items, |
199 | 3627 | 'status_value': self.context.status.title, | 3621 | importance_value=cx.importance.title, |
200 | 3628 | 'importance_widget_items': self.importance_widget_items, | 3622 | milestone_widget_items=self.milestone_widget_items, |
201 | 3629 | 'importance_value': self.context.importance.title, | 3623 | milestone_value=( |
202 | 3630 | 'milestone_widget_items': self.milestone_widget_items, | 3624 | canonical_url( |
203 | 3631 | 'milestone_value': (self.context.milestone and | 3625 | cx.milestone, |
204 | 3632 | canonical_url( | 3626 | request=IWebServiceClientRequest(self.request)) |
205 | 3633 | self.context.milestone, | 3627 | if cx.milestone else None), |
206 | 3634 | request=IWebServiceClientRequest( | 3628 | user_can_edit_assignee=self.user_can_edit_assignee, |
207 | 3635 | self.request)) or | 3629 | user_can_edit_milestone=self.user_can_edit_milestone, |
208 | 3636 | None), | 3630 | user_can_edit_status=not cx.bugwatch, |
209 | 3637 | 'user_can_edit_assignee': self.user_can_edit_assignee, | 3631 | user_can_edit_importance=( |
210 | 3638 | 'user_can_edit_milestone': self.user_can_edit_milestone, | 3632 | self.user_can_edit_importance and not cx.bugwatch) |
211 | 3639 | 'user_can_edit_status': not self.context.bugwatch, | 3633 | )) |
181 | 3640 | 'user_can_edit_importance': ( | ||
182 | 3641 | self.user_can_edit_importance and | ||
183 | 3642 | not self.context.bugwatch)}) | ||
212 | 3643 | 3634 | ||
213 | 3644 | 3635 | ||
214 | 3645 | class BugsBugTaskSearchListingView(BugTaskSearchListingView): | 3636 | class BugsBugTaskSearchListingView(BugTaskSearchListingView): |
215 | 3646 | 3637 | ||
216 | === modified file 'lib/lp/bugs/browser/configure.zcml' | |||
217 | --- lib/lp/bugs/browser/configure.zcml 2011-08-16 14:21:39 +0000 | |||
218 | +++ lib/lp/bugs/browser/configure.zcml 2011-08-23 01:53:28 +0000 | |||
219 | @@ -564,8 +564,7 @@ | |||
220 | 564 | for="lp.bugs.interfaces.bugtask.IBugTask" | 564 | for="lp.bugs.interfaces.bugtask.IBugTask" |
221 | 565 | class="lp.bugs.browser.bugtask.BugTaskTableRowView" | 565 | class="lp.bugs.browser.bugtask.BugTaskTableRowView" |
222 | 566 | permission="launchpad.View" | 566 | permission="launchpad.View" |
225 | 567 | name="+bugtasks-and-nominations-table-row" | 567 | name="+bugtasks-and-nominations-table-row"/> |
224 | 568 | template="../templates/bugtask-tasks-and-nominations-table-row.pt"/> | ||
226 | 569 | <browser:page | 568 | <browser:page |
227 | 570 | for="lp.bugs.interfaces.bugtarget.IBugTarget" | 569 | for="lp.bugs.interfaces.bugtarget.IBugTarget" |
228 | 571 | permission="zope.Public" | 570 | permission="zope.Public" |
229 | 572 | 571 | ||
230 | === modified file 'lib/lp/bugs/templates/bugtask-tasks-and-nominations-table-row.pt' | |||
231 | --- lib/lp/bugs/templates/bugtask-tasks-and-nominations-table-row.pt 2011-08-10 16:14:13 +0000 | |||
232 | +++ lib/lp/bugs/templates/bugtask-tasks-and-nominations-table-row.pt 2011-08-23 01:53:28 +0000 | |||
233 | @@ -1,44 +1,30 @@ | |||
234 | 1 | <tal:bugtask | 1 | <tal:bugtask |
235 | 2 | xmlns:tal="http://xml.zope.org/namespaces/tal" | 2 | xmlns:tal="http://xml.zope.org/namespaces/tal" |
236 | 3 | xmlns:metal="http://xml.zope.org/namespaces/metal" | 3 | xmlns:metal="http://xml.zope.org/namespaces/metal" |
245 | 4 | define="expandable view/expandable; | 4 | define="data view/data"> |
246 | 5 | indent_task view/shouldIndentTask; | 5 | <tr tal:attributes="class data/row_css_class; id data/row_id"> |
239 | 6 | is_conjoined_slave view/is_conjoined_slave; | ||
240 | 7 | tasklink view/taskLink; | ||
241 | 8 | row_id string:tasksummary${context/id}; | ||
242 | 9 | form_row_id string:task${context/id}"> | ||
243 | 10 | <tr tal:define="editstatus_url string:${context/fmt:url}/+editstatus" | ||
244 | 11 | tal:attributes="class view/getTaskRowCSSClass; id row_id"> | ||
247 | 12 | <td> | 6 | <td> |
259 | 13 | <metal:expander | 7 | <a tal:condition="data/expandable" |
260 | 14 | metal:define-macro="expander" | 8 | tal:attributes="href data/task_link" class="bugtask-expander"> |
261 | 15 | tal:define="expander_link_text expander_link_text|nothing"> | 9 | ​ |
262 | 16 | <a tal:condition="expandable" | 10 | </a> |
252 | 17 | tal:attributes="href tasklink" class="bugtask-expander"> | ||
253 | 18 | <tal:link_text tal:replace="expander_link_text" /> | ||
254 | 19 | ​ | ||
255 | 20 | </a> | ||
256 | 21 | <tal:no_expander tal:condition="not: expandable" | ||
257 | 22 | tal:replace="expander_link_text" /> | ||
258 | 23 | </metal:expander> | ||
263 | 24 | </td> | 11 | </td> |
264 | 25 | <td style="padding: 0.3em 0em 0.3em 1.5em" | 12 | <td style="padding: 0.3em 0em 0.3em 1.5em" |
267 | 26 | tal:condition="indent_task" | 13 | tal:condition="data/indent_task"> |
266 | 27 | tal:define="series_targetname view/getSeriesTargetName"> | ||
268 | 28 | <span class="sprite milestone"></span> | 14 | <span class="sprite milestone"></span> |
270 | 29 | <tal:not-conjoined-task condition="not: is_conjoined_slave"> | 15 | <tal:not-conjoined-task condition="not: data/is_conjoined_slave"> |
271 | 30 | <a | 16 | <a |
274 | 31 | tal:attributes="href context/target/fmt:url" | 17 | tal:attributes="href data/target_link" |
275 | 32 | tal:content="series_targetname" | 18 | tal:content="view/getSeriesTargetName" |
276 | 33 | /> | 19 | /> |
277 | 34 | </tal:not-conjoined-task> | 20 | </tal:not-conjoined-task> |
278 | 35 | </td> | 21 | </td> |
281 | 36 | <td tal:condition="not:indent_task"> | 22 | <td tal:condition="not:data/indent_task"> |
282 | 37 | <span tal:attributes="id string:bugtarget-picker-${row_id}"> | 23 | <span tal:attributes="id string:bugtarget-picker-${data/row_id}"> |
283 | 38 | <span class="yui3-activator-data-box"> | 24 | <span class="yui3-activator-data-box"> |
284 | 39 | <span title="This project’s license has not been specified."> | 25 | <span title="This project’s license has not been specified."> |
287 | 40 | <a tal:attributes="href context/target/fmt:url; | 26 | <a tal:attributes="href data/target_link; |
288 | 41 | title view/target_link_title; | 27 | title data/target_link_title; |
289 | 42 | class context/target/image:sprite_css" | 28 | class context/target/image:sprite_css" |
290 | 43 | tal:content="context/bugtargetdisplayname" /> | 29 | tal:content="context/bugtargetdisplayname" /> |
291 | 44 | </span> | 30 | </span> |
292 | @@ -50,7 +36,7 @@ | |||
293 | 50 | </span> | 36 | </span> |
294 | 51 | </td> | 37 | </td> |
295 | 52 | 38 | ||
297 | 53 | <tal:conjoined-task condition="is_conjoined_slave"> | 39 | <tal:conjoined-task condition="data/is_conjoined_slave"> |
298 | 54 | <td colspan="5" style="vertical-align: middle"> | 40 | <td colspan="5" style="vertical-align: middle"> |
299 | 55 | <span class="discreet lesser" style="font-size: 100%"> | 41 | <span class="discreet lesser" style="font-size: 100%"> |
300 | 56 | Status tracked in | 42 | Status tracked in |
301 | @@ -61,79 +47,85 @@ | |||
302 | 61 | </td> | 47 | </td> |
303 | 62 | </tal:conjoined-task> | 48 | </tal:conjoined-task> |
304 | 63 | 49 | ||
306 | 64 | <tal:not-conjoined-task condition="not:is_conjoined_slave"> | 50 | <tal:not-conjoined-task condition="not:data/is_conjoined_slave"> |
307 | 65 | <td style="width: 20%; vertical-align: middle"> | 51 | <td style="width: 20%; vertical-align: middle"> |
308 | 66 | <div class="status-content" | 52 | <div class="status-content" |
310 | 67 | style="width: 100%; float: left"> | 53 | style="width: 100%; float: left" |
311 | 54 | tal:define="status context/status"> | ||
312 | 68 | <a href="+editstatus" | 55 | <a href="+editstatus" |
315 | 69 | tal:attributes="class string:value status${context/status/name}; | 56 | tal:attributes="class string:value status${status/name}; |
316 | 70 | href editstatus_url" | 57 | href data/edit_link" |
317 | 71 | style="float: left" | 58 | style="float: left" |
319 | 72 | tal:content="context/status/title" /> | 59 | tal:content="status/title" /> |
320 | 73 | <a href="+editstatus" style="margin-left: 3px" | 60 | <a href="+editstatus" style="margin-left: 3px" |
322 | 74 | tal:attributes="href editstatus_url"> | 61 | tal:attributes="href data/edit_link"> |
323 | 75 | <img class="editicon" src="/@@/edit" /> | 62 | <img class="editicon" src="/@@/edit" /> |
324 | 76 | </a> | 63 | </a> |
325 | 77 | </div> | 64 | </div> |
326 | 78 | </td> | 65 | </td> |
327 | 79 | 66 | ||
329 | 80 | <td tal:condition="view/user_can_edit_importance" | 67 | <td tal:condition="data/user_can_edit_importance" |
330 | 81 | style="width: 20%; vertical-align: middle"> | 68 | style="width: 20%; vertical-align: middle"> |
331 | 82 | <div class="importance-content" | 69 | <div class="importance-content" |
332 | 83 | style="width: 100%; float: left"> | 70 | style="width: 100%; float: left"> |
333 | 84 | <a href="+editstatus" | 71 | <a href="+editstatus" |
336 | 85 | tal:attributes="class string:value importance${context/importance/name}; | 72 | tal:attributes="class string:value ${data/importance_css_class}; |
337 | 86 | href editstatus_url" | 73 | href data/edit_link" |
338 | 87 | style="float: left" | 74 | style="float: left" |
340 | 88 | tal:content="context/importance/title" /> | 75 | tal:content="data/importance_title" /> |
341 | 89 | <a href="+editstatus" style="margin-left: 3px" | 76 | <a href="+editstatus" style="margin-left: 3px" |
343 | 90 | tal:attributes="href editstatus_url"> | 77 | tal:attributes="href data/edit_link"> |
344 | 91 | <img class="editicon" src="/@@/edit" /> | 78 | <img class="editicon" src="/@@/edit" /> |
345 | 92 | </a> | 79 | </a> |
346 | 93 | </div> | 80 | </div> |
347 | 94 | </td> | 81 | </td> |
349 | 95 | <td tal:condition="not: view/user_can_edit_importance" | 82 | <td tal:condition="not: data/user_can_edit_importance" |
350 | 96 | style="width: 15em; vertical-align: middle"> | 83 | style="width: 15em; vertical-align: middle"> |
351 | 97 | <div class="importance-content" | 84 | <div class="importance-content" |
352 | 98 | style="width: 100%; float: left"> | 85 | style="width: 100%; float: left"> |
353 | 99 | <span | 86 | <span |
355 | 100 | tal:attributes="class string:value importance${context/importance/name}" | 87 | tal:attributes="class string:value ${data/importance_css_class}" |
356 | 101 | style="float: left" | 88 | style="float: left" |
358 | 102 | tal:content="context/importance/title" /> | 89 | tal:content="data/importance_title" /> |
359 | 103 | </div> | 90 | </div> |
360 | 104 | </td> | 91 | </td> |
361 | 105 | 92 | ||
362 | 106 | <td style="width:20%; margin: 0; padding: 0; | 93 | <td style="width:20%; margin: 0; padding: 0; |
378 | 107 | vertical-align: middle; padding-left: 0.5em"> | 94 | vertical-align: middle; padding-left: 0.5em" |
379 | 108 | <tal:has_watch condition="context/bugwatch"> | 95 | tal:define="bugwatch context/bugwatch;"> |
380 | 109 | <div style="text-decoration: none; padding: 0.25em"> | 96 | <tal:has_watch condition="bugwatch"> |
381 | 110 | <tal:bugtracker-active | 97 | <div style="text-decoration: none; padding: 0.25em" |
382 | 111 | condition="context/bugwatch/bugtracker/active"> | 98 | tal:define="active_bugtracker bugwatch/bugtracker/active;"> |
383 | 112 | <span tal:condition="not:context/bugwatch/last_error_type" | 99 | <tal:bugtracker-active condition="active_bugtracker"> |
384 | 113 | class="sprite bug-remote"></span> | 100 | <tal:block define="last_error_type bugwatch/last_error_type;"> |
385 | 114 | <a tal:condition="context/bugwatch/last_error_type" | 101 | <span tal:condition="not:last_error_type" |
386 | 115 | tal:attributes="href view/bug_watch_error_message/help_url" | 102 | class="sprite bug-remote"></span> |
387 | 116 | target="help" | 103 | <a tal:condition="last_error_type" |
388 | 117 | class="icon help"> | 104 | tal:attributes="href view/bug_watch_error_message/help_url" |
389 | 118 | <span class="sprite warning-icon" | 105 | target="help" |
390 | 119 | tal:attributes="title view/bug_watch_error_message/message" | 106 | class="icon help"> |
391 | 120 | id="bugwatch-error-sprite"></span> | 107 | <span class="sprite warning-icon" |
392 | 121 | </a> | 108 | tal:attributes= |
393 | 109 | "title view/bug_watch_error_message/message" | ||
394 | 110 | id="bugwatch-error-sprite"></span> | ||
395 | 111 | </a> | ||
396 | 112 | </tal:block> | ||
397 | 122 | </tal:bugtracker-active> | 113 | </tal:bugtracker-active> |
399 | 123 | <span tal:condition="not:context/bugwatch/bugtracker/active" | 114 | <span tal:condition="not:active_bugtracker" |
400 | 124 | class="sprite warning-icon"></span> | 115 | class="sprite warning-icon"></span> |
402 | 125 | <a tal:replace="structure context/bugwatch/fmt:external-link" /> | 116 | <a tal:replace="structure bugwatch/fmt:external-link" /> |
403 | 126 | </div> | 117 | </div> |
404 | 127 | </tal:has_watch> | 118 | </tal:has_watch> |
405 | 128 | 119 | ||
408 | 129 | <tal:has_no_watch condition="not: context/bugwatch"> | 120 | <tal:has_no_watch condition="not: bugwatch"> |
409 | 130 | <span tal:attributes="id string:assignee-picker-${row_id}"> | 121 | <span tal:attributes="id string:assignee-picker-${data/row_id}" |
410 | 122 | tal:define="assignee context/assignee"> | ||
411 | 131 | <span class="yui3-activator-data-box"> | 123 | <span class="yui3-activator-data-box"> |
417 | 132 | <a tal:condition="context/assignee" | 124 | <a tal:condition="assignee" |
418 | 133 | tal:attributes="href context/assignee/fmt:url; | 125 | tal:attributes="href assignee/fmt:url; |
419 | 134 | class context/assignee/image:sprite_css" | 126 | class assignee/image:sprite_css" |
420 | 135 | tal:content="context/assignee/fmt:displayname" /> | 127 | tal:content="assignee/fmt:displayname" /> |
421 | 136 | <tal:unassigned condition="not: context/assignee"> | 128 | <tal:unassigned condition="not: assignee"> |
422 | 137 | Unassigned | 129 | Unassigned |
423 | 138 | </tal:unassigned> | 130 | </tal:unassigned> |
424 | 139 | </span> | 131 | </span> |
425 | @@ -147,11 +139,11 @@ | |||
426 | 147 | 139 | ||
427 | 148 | <td style="width: 20%; vertical-align: middle"> | 140 | <td style="width: 20%; vertical-align: middle"> |
428 | 149 | <div class="milestone-content" | 141 | <div class="milestone-content" |
430 | 150 | tal:condition="view/target_has_milestones" | 142 | tal:condition="data/target_has_milestones" |
431 | 151 | style="width: 100%; float: left"> | 143 | style="width: 100%; float: left"> |
432 | 152 | <a tal:condition="view/user_can_edit_milestone" | 144 | <a tal:condition="view/user_can_edit_milestone" |
433 | 153 | class="nulltext addicon js-action sprite add" | 145 | class="nulltext addicon js-action sprite add" |
435 | 154 | tal:attributes="href editstatus_url; | 146 | tal:attributes="href data/edit_link; |
436 | 155 | style view/style_for_add_milestone"> | 147 | style view/style_for_add_milestone"> |
437 | 156 | Target to milestone | 148 | Target to milestone |
438 | 157 | </a> | 149 | </a> |
439 | @@ -159,7 +151,7 @@ | |||
440 | 159 | tal:attributes="href context/milestone/fmt:url | nothing" | 151 | tal:attributes="href context/milestone/fmt:url | nothing" |
441 | 160 | tal:content="context/milestone/title | nothing" /> | 152 | tal:content="context/milestone/title | nothing" /> |
442 | 161 | <a tal:condition="view/user_can_edit_milestone" | 153 | <a tal:condition="view/user_can_edit_milestone" |
444 | 162 | tal:attributes="href editstatus_url" | 154 | tal:attributes="href data/edit_link" |
445 | 163 | ><img class="editicon" src="/@@/edit" | 155 | ><img class="editicon" src="/@@/edit" |
446 | 164 | tal:attributes="style view/style_for_edit_milestone" | 156 | tal:attributes="style view/style_for_edit_milestone" |
447 | 165 | /></a> | 157 | /></a> |
448 | @@ -178,8 +170,8 @@ | |||
449 | 178 | Y.lp.bugs.bugtask_index.setup_bugtask_row(${view/js_config}); | 170 | Y.lp.bugs.bugtask_index.setup_bugtask_row(${view/js_config}); |
450 | 179 | 171 | ||
451 | 180 | // Set-up the expander on the bug task summary row. | 172 | // Set-up the expander on the bug task summary row. |
454 | 181 | var icon_node = Y.one('tr#${row_id} a.bugtask-expander'); | 173 | var icon_node = Y.one('tr#${data/row_id} a.bugtask-expander'); |
455 | 182 | var row_node = Y.one('tr#${form_row_id}'); | 174 | var row_node = Y.one('tr#${data/form_row_id}'); |
456 | 183 | if (Y.Lang.isValue(row_node)) { | 175 | if (Y.Lang.isValue(row_node)) { |
457 | 184 | // When no row is present, this is bug task on a project with | 176 | // When no row is present, this is bug task on a project with |
458 | 185 | // multiple per-series tasks, so we do not need to set | 177 | // multiple per-series tasks, so we do not need to set |
459 | @@ -195,8 +187,8 @@ | |||
460 | 195 | 187 | ||
461 | 196 | <tal:form condition="view/displayEditForm"> | 188 | <tal:form condition="view/displayEditForm"> |
462 | 197 | <tr | 189 | <tr |
465 | 198 | tal:attributes="id form_row_id" | 190 | tal:attributes="id data/form_row_id" |
466 | 199 | tal:condition="expandable" | 191 | tal:condition="data/expandable" |
467 | 200 | class="bugtask-collapsible-content unseen" | 192 | class="bugtask-collapsible-content unseen" |
468 | 201 | > | 193 | > |
469 | 202 | <td colspan="7" tal:content="structure view/edit_view" /> | 194 | <td colspan="7" tal:content="structure view/edit_view" /> |
470 | 203 | 195 | ||
471 | === modified file 'setup.py' | |||
472 | --- setup.py 2011-08-21 22:06:09 +0000 | |||
473 | +++ setup.py 2011-08-23 01:53:28 +0000 | |||
474 | @@ -29,8 +29,7 @@ | |||
475 | 29 | 'ampoule', | 29 | 'ampoule', |
476 | 30 | 'BeautifulSoup', | 30 | 'BeautifulSoup', |
477 | 31 | 'bzr', | 31 | 'bzr', |
480 | 32 | 'chameleon.core', | 32 | 'Chameleon', |
479 | 33 | 'chameleon.zpt', | ||
481 | 34 | 'cssutils', | 33 | 'cssutils', |
482 | 35 | # Required for pydkim | 34 | # Required for pydkim |
483 | 36 | 'dnspython', | 35 | 'dnspython', |
484 | 37 | 36 | ||
485 | === modified file 'versions.cfg' | |||
486 | --- versions.cfg 2011-08-22 07:09:21 +0000 | |||
487 | +++ versions.cfg 2011-08-23 01:53:28 +0000 | |||
488 | @@ -8,8 +8,7 @@ | |||
489 | 8 | amqplib = 0.6.1 | 8 | amqplib = 0.6.1 |
490 | 9 | BeautifulSoup = 3.1.0.1 | 9 | BeautifulSoup = 3.1.0.1 |
491 | 10 | bzr = 2.3.3 | 10 | bzr = 2.3.3 |
494 | 11 | chameleon.core = 1.0b35 | 11 | Chameleon = 2.4.0 |
493 | 12 | chameleon.zpt = 1.0b17 | ||
495 | 13 | ClientForm = 0.2.10 | 12 | ClientForm = 0.2.10 |
496 | 14 | cssutils = 0.9.6 | 13 | cssutils = 0.9.6 |
497 | 15 | docutils = 0.5 | 14 | docutils = 0.5 |
498 | @@ -52,6 +51,7 @@ | |||
499 | 52 | oops = 0.0.6 | 51 | oops = 0.0.6 |
500 | 53 | oops-datedir-repo = 0.0.3 | 52 | oops-datedir-repo = 0.0.3 |
501 | 54 | oops-wsgi = 0.0.2 | 53 | oops-wsgi = 0.0.2 |
502 | 54 | ordereddict = 1.1 | ||
503 | 55 | paramiko = 1.7.4 | 55 | paramiko = 1.7.4 |
504 | 56 | Paste = 1.7.2 | 56 | Paste = 1.7.2 |
505 | 57 | PasteDeploy = 1.3.3 | 57 | PasteDeploy = 1.3.3 |
506 | @@ -91,6 +91,7 @@ | |||
507 | 91 | transaction = 1.0.0 | 91 | transaction = 1.0.0 |
508 | 92 | txamqp = 0.4 | 92 | txamqp = 0.4 |
509 | 93 | Twisted = 11.0.0 | 93 | Twisted = 11.0.0 |
510 | 94 | unittest2 = 0.5.1 | ||
511 | 94 | uuid = 1.30 | 95 | uuid = 1.30 |
512 | 95 | van.testing = 2.0.1 | 96 | van.testing = 2.0.1 |
513 | 96 | wadllib = 1.2.0 | 97 | wadllib = 1.2.0 |
514 | @@ -116,7 +117,7 @@ | |||
515 | 116 | z3c.menu = 0.2.0 | 117 | z3c.menu = 0.2.0 |
516 | 117 | z3c.optionstorage = 1.0.4 | 118 | z3c.optionstorage = 1.0.4 |
517 | 118 | z3c.pagelet = 1.0.2 | 119 | z3c.pagelet = 1.0.2 |
519 | 119 | z3c.pt = 1.0b16 | 120 | z3c.pt = 2.1.3 |
520 | 120 | z3c.ptcompat = 0.5.3 | 121 | z3c.ptcompat = 0.5.3 |
521 | 121 | z3c.recipe.filetemplate = 2.1.0 | 122 | z3c.recipe.filetemplate = 2.1.0 |
522 | 122 | z3c.recipe.i18n = 0.5.3 | 123 | z3c.recipe.i18n = 0.5.3 |
This should have been [incr]. :-/