Merge lp:~gmb/launchpad/subscribers-timeout-bug-471974 into lp:launchpad

Proposed by Graham Binns
Status: Merged
Approved by: Graham Binns
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~gmb/launchpad/subscribers-timeout-bug-471974
Merge into: lp:launchpad
Diff against target: 255 lines (+122/-17)
7 files modified
lib/canonical/launchpad/javascript/bugs/bugtask-index.js (+60/-9)
lib/lp/bugs/browser/bug.py (+0/-6)
lib/lp/bugs/browser/bugsubscription.py (+14/-0)
lib/lp/bugs/browser/configure.zcml (+5/-0)
lib/lp/bugs/browser/tests/bug-subscription-views.txt (+40/-0)
lib/lp/bugs/templates/bug-portlet-subscribers.pt (+3/-0)
lib/lp/bugs/templates/bugtask-index.pt (+0/-2)
To merge this branch: bzr merge lp:~gmb/launchpad/subscribers-timeout-bug-471974
Reviewer Review Type Date Requested Status
Gavin Panella (community) js Approve
Brad Crittenden (community) code Approve
Review via email: mp+14955@code.launchpad.net

Commit message

The subscriber-IDs-to-CSS-ids mapping will now be loaded when the bug subscribers portlet is loaded, rather than being loaded with the page and potentially causing a timeout.

To post a comment you must log in.
Revision history for this message
Graham Binns (gmb) wrote :
Download full text (3.3 KiB)

This branch fixes bug 471974 by moving the loading of the JSON struct of
subscriber IDs out of the main bug page template. Instead, we'll now
lazily-load it when we actually need it - i.e. when we're loading the
subscribers portlet.

The lazy-loading involves requesting a JSON dump from the server, via a
view designed precisely for that task. This seems a bit hacky, but it's
the quickest way to solve the problem. We will investigate more elegant
solutions later.

The upshot of this is that we shouldn't see any more timeouts on the bug
page due to large numbers of subscribers (especially from dupes).

= Launchpad lint =

Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.

Linting changed files:
  lib/canonical/launchpad/javascript/bugs/bugtask-index.js
  lib/lp/bugs/browser/bug.py
  lib/lp/bugs/browser/bugsubscription.py
  lib/lp/bugs/browser/configure.zcml
  lib/lp/bugs/templates/bug-portlet-subscribers-ids.pt
  lib/lp/bugs/templates/bug-portlet-subscribers.pt
  lib/lp/bugs/templates/bugtask-index.pt

== JSLint notices ==
jslint: No problem found in '/home/graham/canonical/lp-branches/subscribers-timeout-bug-471974/lib/canonical/launchpad/javascript/bugs/bugtask-index.js'.

jslint: 1 file to lint.

== Pylint notices ==

lib/lp/bugs/browser/bug.py
    28: [F0401] Unable to import 'email.MIMEMultipart' (No module named MIMEMultipart)
    29: [F0401] Unable to import 'email.MIMEText' (No module named MIMEText)
    43: [F0401] Unable to import 'lazr.enum' (No module named enum)
    44: [F0401] Unable to import 'lazr.lifecycle.event' (No module named lifecycle)
    45: [F0401] Unable to import 'lazr.lifecycle.snapshot' (No module named lifecycle)
    46: [F0401] Unable to import 'lazr.restful.interfaces' (No module named restful)

lib/lp/bugs/browser/bugsubscription.py
    16: [F0401] Unable to import 'lazr.delegates' (No module named delegates)
    17: [F0401] Unable to import 'lazr.lifecycle.event' (No module named lifecycle)

= Changes made =

== lib/canonical/launchpad/javascript/bugs/bugtask-index.js ==

 - I've added Javascript to load the subscriber_ids struct just before
   loading the contents of the subscribers portlet. This should stop the
   bug page from timing out.
 - Note that, should loading the subscriber ids from the JSON dump time
   out (which is theoretically possible), the portlet will still load.

== lib/lp/bugs/browser/bug.py ==

 - I've removed the subscriber_ids_json property from the BugViewMixin.
   It belongs specifically in our JSON-dumping view.

== lib/lp/bugs/browser/bugsubscription.py ==

 - I've added a BugPortletSubscribersIds view. This contains a
   subscriber_ids_json property, which returns a JSON dump of the
   subscriber IDs for the current bug.

== lib/lp/bugs/browser/configure.zcml ==

 - I've added the ZCML for the new view.

== lib/lp/bugs/templates/bug-portlet-subscribers-ids.pt ==

 - I've added this view to contain the JSON dump.

== lib/lp/bugs/templates/bug-portlet-subscribers.pt ==

 - I've added a link to the bug-portlet-subscribers-ids URL so that we
   can grab it using JS and load the JSON dump from it.

== lib...

Read more...

Revision history for this message
Brad Crittenden (bac) wrote :

Hi Graham,

Thanks for this fix. I note there are two issues. One, the icon and subscriber name now appear on different lines and for the life of me I cannot figure out why.

Also I'm bothered that a change of this size has no tests. You could do a view test to check the results of your new view. What about Windmill tests?

Perhaps it is just the current state of affairs but the fragility of this change bothers me.

I've removed the 'js' portion from this review as you may want to get an expert to do that portion.

review: Needs Information (code)
Revision history for this message
Graham Binns (gmb) wrote :
Download full text (3.3 KiB)

On Tue, Nov 17, 2009 at 08:08:18PM -0000, Brad Crittenden wrote:
> Review: Needs Information code
> Hi Graham,

Hi Brad, thanks for the review.

> Thanks for this fix. I note there are two issues. One, the icon and
> subscriber name now appear on different lines and for the life of me I
> cannot figure out why.

That's not a result of this branch; you can see the same behaviour on
edge at the moment. I'll file a bug about it.

>
> Also I'm bothered that a change of this size has no tests. You could
> do a view test to check the results of your new view. What about
> Windmill tests?
>

You're quite right. I've added a view test for the JSON dump (See below
for diff). The changes should still pass the current windmill test
suite, though IIRC the inline subscribers part of the tests is currently
failing anyway, so it's difficult to tell. I'll run it through windmill
before landing.

> Perhaps it is just the current state of affairs but the fragility of
> this change bothers me.
>

I don't think the change is particularly fragile. I designed it
specifically so that if fetching the IDs fails we'll just fall back to
loading the portlet anyway. The only time someone will have a noticeable
problem in that case is if they try to subscribe and unsubscribe quickly
in succession (in which case the subscribe / unsubscribe link may not
update properly) or if they try to unsubscribe from a dupe, in which
case they'll have to do it via the old +subscribe form rather than via
AJAX.

Can you be more specific about the fragility that concerns you?

> I've removed the 'js' portion from this review as you may want to get
> an expert to do that portion.

I'll ask Gavin to take a look since he's OCR today.

Incremental diff of changes
---------------------------

=== added file 'lib/lp/bugs/browser/tests/bug-subscription-views.txt'
--- lib/lp/bugs/browser/tests/bug-subscription-views.txt 1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/browser/tests/bug-subscription-views.txt 2009-11-18 11:50:28 +0000
@@ -0,0 +1,40 @@
+Bug subscription views
+======================
+
+Getting subscriber CSS IDs
+--------------------------
+
+It's possible to get a mapping of bug subscriber names to CSS IDs using
+the +bug-portlet-subscribers-ids view.
+
+ >>> from lp.bugs.interfaces.bug import IBugSet
+ >>> bug_15 = getUtility(IBugSet).get(15)
+
+ >>> subscriber_ids_view = create_initialized_view(
+ ... bug_15, '+bug-portlet-subscribers-ids')
+
+The view's subscriber_ids_js property returns a JSON struct of the
+person name to CSS ID mappings for the bug's subscribers.
+
+ >>> print subscriber_ids_view.subscriber_ids_js
+ {"name16": "subscriber-16"}
+
+If bug 15 is marked as a duplicate of another bug, its subscribers will
+be included in that bugs subscriber_ids_js mapping.
+
+ >>> bug_13 = getUtility(IBugSet).get(13)
+ >>> subscriber_ids_view = create_initialized_view(
+ ... bug_13, '+bug-portlet-subscribers-ids')
+
+ >>> print subscriber_ids_view.subscriber_ids_js
+ {"name12": "subscriber-12"}
+
+ >>> login('<email address hidden>')
+ >>> bug_15.duplicateof = bug_13
+ >>> bug_13 = getUtility(IBugSet).get(13)
+
+ >>> subscriber...

Read more...

Revision history for this message
Graham Binns (gmb) wrote :
Download full text (5.4 KiB)

Here's an incremental diff of the changes that Gavin suggested on IRC:

=== modified file 'lib/canonical/launchpad/javascript/bugs/bugtask-index.js'
--- lib/canonical/launchpad/javascript/bugs/bugtask-index.js 2009-11-17 16:00:21 +0000
+++ lib/canonical/launchpad/javascript/bugs/bugtask-index.js 2009-11-18 15:20:12 +0000
@@ -54,8 +54,7 @@
 Y.augment(PortletTarget, Y.Event.Target);
 Y.bugs.portlet = new PortletTarget();
 Y.bugs.portlet.subscribe('bugs:portletloaded', function() {
- setup_subscription_link_handlers();
- load_subscribers_from_duplicates();
+ load_subscriber_ids();
 });
 Y.bugs.portlet.subscribe('bugs:dupeportletloaded', function() {
     setup_unsubscribe_icon_handlers();
@@ -78,6 +77,22 @@
     setup_unsubscribe_icon_handlers();
 });

+/* If loading the subscriber IDs JSON has succeeded, set up the
+ * subscription link handlers and load the subscribers from dupes.
+ */
+Y.bugs.portlet.subscribe('bugs:portletsubscriberidsloaded', function() {
+ setup_subscription_link_handlers();
+ load_subscribers_from_duplicates();
+});
+
+/* If loading the subscriber IDs JSON fails we still need to load the
+ * subscribers from duplicates but we don't set up the subscription link
+ * handlers.
+ */
+Y.bugs.portlet.subscribe('bugs:portletsubscriberidsfailed', function() {
+ load_subscribers_from_duplicates();
+});
+
 /*
  * Subscribing someone else requires loading a grayed out
  * username into the DOM until the subscribe action completes.
@@ -1806,35 +1821,44 @@
         Y.bugs.portlet.fire('bugs:portletloaded');
     }

- function load_portlet() {
- var config = {on: {success: setup_portlet,
- failure: hide_spinner}};
- var url = Y.get(
- '#subscribers-content-link').getAttribute('href').replace(
- 'bugs.', '');
- Y.io(url, config);
- }
+ var config = {on: {success: setup_portlet,
+ failure: hide_spinner}};
+ var url = Y.get(
+ '#subscribers-content-link').getAttribute('href').replace(
+ 'bugs.', '');
+ Y.io(url, config);
+};

- function load_subscriber_ids(transactionid, response, args) {
+function load_subscriber_ids() {
+ function on_success(transactionid, response, args) {
         try {
- var subscriber_ids_node = Y.Node.create(
- response.responseText);
- var subscriber_ids_json = subscriber_ids_node.get('innerHTML');
- subscriber_ids = Y.JSON.parse(subscriber_ids_json);
+ subscriber_ids = Y.JSON.parse(response.responseText);
+ Y.log("Loaded subscriber IDs.");
+
+ // Fire a custom event to trigger the setting-up of the
+ // subscription handlers.
+ Y.bugs.portlet.fire('bugs:portletsubscriberidsloaded');
         } catch (e) {
             Y.log("Unable to load subscriber ids.", "error");
+
+ // Fire an event to signal failure. This ensures that the
+ // subscribers-from-dupes still get loaded into the portlet.
+ Y.bugs.portlet.fire('bugs:portletsubscriberidsfailed');
         }
-
- load_portlet();
- }
-
- var config = {on: {success: lo...

Read more...

Revision history for this message
Brad Crittenden (bac) wrote :

Thanks for adding the view test Graham. I'm satisfied with the code portion and I know Gavin and you have a handle on the JS parts.

review: Approve (code)
Revision history for this message
Gavin Panella (allenap) :
review: Approve (js)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/canonical/launchpad/javascript/bugs/bugtask-index.js'
--- lib/canonical/launchpad/javascript/bugs/bugtask-index.js 2009-11-14 21:14:40 +0000
+++ lib/canonical/launchpad/javascript/bugs/bugtask-index.js 2009-11-18 15:53:11 +0000
@@ -39,6 +39,9 @@
39var privacy_spinner;39var privacy_spinner;
40var link_branch_link;40var link_branch_link;
4141
42// The set of subscriber CSS IDs as a JSON struct.
43var subscriber_ids;
44
42/*45/*
43 * An object representing the bugtask subscribers portlet.46 * An object representing the bugtask subscribers portlet.
44 *47 *
@@ -51,8 +54,7 @@
51Y.augment(PortletTarget, Y.Event.Target);54Y.augment(PortletTarget, Y.Event.Target);
52Y.bugs.portlet = new PortletTarget();55Y.bugs.portlet = new PortletTarget();
53Y.bugs.portlet.subscribe('bugs:portletloaded', function() {56Y.bugs.portlet.subscribe('bugs:portletloaded', function() {
54 setup_subscription_link_handlers();57 load_subscriber_ids();
55 load_subscribers_from_duplicates();
56});58});
57Y.bugs.portlet.subscribe('bugs:dupeportletloaded', function() {59Y.bugs.portlet.subscribe('bugs:dupeportletloaded', function() {
58 setup_unsubscribe_icon_handlers();60 setup_unsubscribe_icon_handlers();
@@ -75,6 +77,22 @@
75 setup_unsubscribe_icon_handlers();77 setup_unsubscribe_icon_handlers();
76});78});
7779
80/* If loading the subscriber IDs JSON has succeeded, set up the
81 * subscription link handlers and load the subscribers from dupes.
82 */
83Y.bugs.portlet.subscribe('bugs:portletsubscriberidsloaded', function() {
84 setup_subscription_link_handlers();
85 load_subscribers_from_duplicates();
86});
87
88/* If loading the subscriber IDs JSON fails we still need to load the
89 * subscribers from duplicates but we don't set up the subscription link
90 * handlers.
91 */
92Y.bugs.portlet.subscribe('bugs:portletsubscriberidsfailed', function() {
93 load_subscribers_from_duplicates();
94});
95
78/*96/*
79 * Subscribing someone else requires loading a grayed out97 * Subscribing someone else requires loading a grayed out
80 * username into the DOM until the subscribe action completes.98 * username into the DOM until the subscribe action completes.
@@ -1792,7 +1810,7 @@
1792 }1810 }
1793 }1811 }
17941812
1795 function on_success(transactionid, response, args) {1813 function setup_portlet(transactionid, response, args) {
1796 hide_spinner();1814 hide_spinner();
1797 var portlet = Y.get('#portlet-subscribers');1815 var portlet = Y.get('#portlet-subscribers');
1798 portlet.set('innerHTML',1816 portlet.set('innerHTML',
@@ -1803,16 +1821,49 @@
1803 Y.bugs.portlet.fire('bugs:portletloaded');1821 Y.bugs.portlet.fire('bugs:portletloaded');
1804 }1822 }
18051823
1806 var config = {on: {success: on_success,1824 var config = {on: {success: setup_portlet,
1807 failure: hide_spinner}};1825 failure: hide_spinner}};
1808 var url = Y.get(1826 var url = Y.get(
1809 '#subscribers-content-link').getAttribute('href').replace('bugs.', '');1827 '#subscribers-content-link').getAttribute('href').replace(
1828 'bugs.', '');
1810 Y.io(url, config);1829 Y.io(url, config);
1811};1830};
18121831
1813}, '0.1', {requires: ['base', 'oop', 'node', 'event', 'io-base', 'substitute',1832function load_subscriber_ids() {
1814 'widget-position-ext', 'lazr.formoverlay', 'lazr.anim',1833 function on_success(transactionid, response, args) {
1815 'lazr.base', 'lazr.overlay', 'lazr.choiceedit',1834 try {
1816 'lp.picker', 'lp.client.plugins', 'lp.subscriber',1835 subscriber_ids = Y.JSON.parse(response.responseText);
1836 Y.log("Loaded subscriber IDs.");
1837
1838 // Fire a custom event to trigger the setting-up of the
1839 // subscription handlers.
1840 Y.bugs.portlet.fire('bugs:portletsubscriberidsloaded');
1841 } catch (e) {
1842 Y.log("Unable to load subscriber ids.", "error");
1843
1844 // Fire an event to signal failure. This ensures that the
1845 // subscribers-from-dupes still get loaded into the portlet.
1846 Y.bugs.portlet.fire('bugs:portletsubscriberidsfailed');
1847 }
1848 }
1849
1850 function on_failure() {
1851 // Fire an event to signal failure. This ensures that the
1852 // subscribers-from-dupes still get loaded into the portlet.
1853 Y.bugs.portlet.fire('bugs:portletsubscriberidsfailed');
1854 }
1855
1856 var config = {on: {success: on_success,
1857 failure: on_failure}};
1858 var url = Y.get(
1859 '#subscribers-ids-link').getAttribute('href');
1860 Y.io(url, config);
1861}
1862
1863}, '0.1', {requires: ['base', 'oop', 'node', 'event', 'io-base', 'json-parse',
1864 'substitute', 'widget-position-ext',
1865 'lazr.formoverlay', 'lazr.anim', 'lazr.base',
1866 'lazr.overlay', 'lazr.choiceedit', 'lp.picker',
1867 'lp.client.plugins', 'lp.subscriber',
1817 'lp.errors']});1868 'lp.errors']});
18181869
18191870
=== modified file 'lib/lp/bugs/browser/bug.py'
--- lib/lp/bugs/browser/bug.py 2009-10-30 16:28:41 +0000
+++ lib/lp/bugs/browser/bug.py 2009-11-18 15:53:11 +0000
@@ -30,7 +30,6 @@
30import re30import re
3131
32import pytz32import pytz
33from simplejson import dumps
3433
35from zope.app.form.browser import TextWidget34from zope.app.form.browser import TextWidget
36from zope.component import adapter, getUtility35from zope.component import adapter, getUtility
@@ -433,11 +432,6 @@
433 ids[sub.name] = 'subscriber-%s' % sub.id432 ids[sub.name] = 'subscriber-%s' % sub.id
434 return ids433 return ids
435434
436 @property
437 def subscriber_ids_js(self):
438 """Return subscriber_ids in a form suitable for JavaScript use."""
439 return dumps(self.subscriber_ids)
440
441 def subscription_class(self, subscribed_person):435 def subscription_class(self, subscribed_person):
442 """Return a set of CSS class names based on subscription status.436 """Return a set of CSS class names based on subscription status.
443437
444438
=== modified file 'lib/lp/bugs/browser/bugsubscription.py'
--- lib/lp/bugs/browser/bugsubscription.py 2009-11-05 19:01:12 +0000
+++ lib/lp/bugs/browser/bugsubscription.py 2009-11-18 15:53:11 +0000
@@ -10,6 +10,7 @@
10 'BugSubscriptionAddView',10 'BugSubscriptionAddView',
11 ]11 ]
1212
13from simplejson import dumps
13from zope.event import notify14from zope.event import notify
1415
15from lazr.delegates import delegates16from lazr.delegates import delegates
@@ -97,6 +98,19 @@
97 for subscription in self.context.getSubscriptionsFromDuplicates()]98 for subscription in self.context.getSubscriptionsFromDuplicates()]
9899
99100
101class BugPortletSubcribersIds(LaunchpadView, BugViewMixin):
102 """A view that returns a JSON dump of the subscriber IDs for a bug."""
103
104 @property
105 def subscriber_ids_js(self):
106 """Return subscriber_ids in a form suitable for JavaScript use."""
107 return dumps(self.subscriber_ids)
108
109 def render(self):
110 """Override the default render() to return only JSON."""
111 return self.subscriber_ids_js
112
113
100class SubscriptionAttrDecorator:114class SubscriptionAttrDecorator:
101 """A BugSubscription with added attributes for HTML/JS."""115 """A BugSubscription with added attributes for HTML/JS."""
102 delegates(IBugSubscription, 'subscription')116 delegates(IBugSubscription, 'subscription')
103117
=== modified file 'lib/lp/bugs/browser/configure.zcml'
--- lib/lp/bugs/browser/configure.zcml 2009-11-10 11:31:06 +0000
+++ lib/lp/bugs/browser/configure.zcml 2009-11-18 15:53:11 +0000
@@ -1004,6 +1004,11 @@
1004 class="lp.bugs.browser.bugsubscription.BugPortletDuplicateSubcribersContents"1004 class="lp.bugs.browser.bugsubscription.BugPortletDuplicateSubcribersContents"
1005 template="../templates/bug-portlet-dupe-subscribers-content.pt"1005 template="../templates/bug-portlet-dupe-subscribers-content.pt"
1006 permission="zope.Public"/>1006 permission="zope.Public"/>
1007 <browser:page
1008 for="lp.bugs.interfaces.bug.IBug"
1009 name="+bug-portlet-subscribers-ids"
1010 class="lp.bugs.browser.bugsubscription.BugPortletSubcribersIds"
1011 permission="zope.Public"/>
1007 <browser:navigation1012 <browser:navigation
1008 module="lp.bugs.browser.bug"1013 module="lp.bugs.browser.bug"
1009 classes="1014 classes="
10101015
=== added file 'lib/lp/bugs/browser/tests/bug-subscription-views.txt'
--- lib/lp/bugs/browser/tests/bug-subscription-views.txt 1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/browser/tests/bug-subscription-views.txt 2009-11-18 15:53:11 +0000
@@ -0,0 +1,40 @@
1Bug subscription views
2======================
3
4Getting subscriber CSS IDs
5--------------------------
6
7It's possible to get a mapping of bug subscriber names to CSS IDs using
8the +bug-portlet-subscribers-ids view.
9
10 >>> from lp.bugs.interfaces.bug import IBugSet
11 >>> bug_15 = getUtility(IBugSet).get(15)
12
13 >>> subscriber_ids_view = create_initialized_view(
14 ... bug_15, '+bug-portlet-subscribers-ids')
15
16The view's subscriber_ids_js property returns a JSON struct of the
17person name to CSS ID mappings for the bug's subscribers.
18
19 >>> print subscriber_ids_view.subscriber_ids_js
20 {"name16": "subscriber-16"}
21
22If bug 15 is marked as a duplicate of another bug, its subscribers will
23be included in that bugs subscriber_ids_js mapping.
24
25 >>> bug_13 = getUtility(IBugSet).get(13)
26 >>> subscriber_ids_view = create_initialized_view(
27 ... bug_13, '+bug-portlet-subscribers-ids')
28
29 >>> print subscriber_ids_view.subscriber_ids_js
30 {"name12": "subscriber-12"}
31
32 >>> login('foo.bar@canonical.com')
33 >>> bug_15.duplicateof = bug_13
34 >>> bug_13 = getUtility(IBugSet).get(13)
35
36 >>> subscriber_ids_view = create_initialized_view(
37 ... bug_13, '+bug-portlet-subscribers-ids')
38
39 >>> print subscriber_ids_view.subscriber_ids_js
40 {"name12": "subscriber-12", "name16": "subscriber-16"}
041
=== modified file 'lib/lp/bugs/templates/bug-portlet-subscribers.pt'
--- lib/lp/bugs/templates/bug-portlet-subscribers.pt 2009-11-05 14:56:01 +0000
+++ lib/lp/bugs/templates/bug-portlet-subscribers.pt 2009-11-18 15:53:11 +0000
@@ -14,6 +14,9 @@
14 <div id="sub-unsub-spinner">Subscribing...</div>14 <div id="sub-unsub-spinner">Subscribing...</div>
15 <div tal:content="structure context_menu/addsubscriber/render" />15 <div tal:content="structure context_menu/addsubscriber/render" />
16 </div>16 </div>
17 <a id="subscribers-ids-link"
18 tal:define="bug context/bug|context"
19 tal:attributes="href bug/fmt:url/+bug-portlet-subscribers-ids"></a>
17 <a id="subscribers-content-link"20 <a id="subscribers-content-link"
18 tal:define="bug context/bug|context"21 tal:define="bug context/bug|context"
19 tal:attributes="href bug/fmt:url/+bug-portlet-subscribers-content"></a>22 tal:attributes="href bug/fmt:url/+bug-portlet-subscribers-content"></a>
2023
=== modified file 'lib/lp/bugs/templates/bugtask-index.pt'
--- lib/lp/bugs/templates/bugtask-index.pt 2009-10-28 06:08:11 +0000
+++ lib/lp/bugs/templates/bugtask-index.pt 2009-11-18 15:53:11 +0000
@@ -10,8 +10,6 @@
10 <script type='text/javascript' tal:content="string:var yui_base='${yui}';" />10 <script type='text/javascript' tal:content="string:var yui_base='${yui}';" />
11 <script type='text/javascript' id='available-official-tags-js'11 <script type='text/javascript' id='available-official-tags-js'
12 tal:content="view/available_official_tags_js" />12 tal:content="view/available_official_tags_js" />
13 <script type="text/javascript"
14 tal:content="string:var subscriber_ids = ${view/subscriber_ids_js};" />
15 <tal:devmode condition="devmode">13 <tal:devmode condition="devmode">
16 <script type="text/javascript"14 <script type="text/javascript"
17 tal:define="lp_js string:${icingroot}/build"15 tal:define="lp_js string:${icingroot}/build"