Merge lp:~wgrant/launchpad/html-wtf into lp:launchpad

Proposed by William Grant on 2012-03-06
Status: Merged
Approved by: William Grant on 2012-03-07
Approved revision: no longer in the source branch.
Merged at revision: 14916
Proposed branch: lp:~wgrant/launchpad/html-wtf
Merge into: lp:launchpad
Diff against target: 419 lines (+94/-80)
13 files modified
lib/lp/app/templates/base-layout-macros.pt (+16/-17)
lib/lp/app/templates/base-layout.pt (+15/-28)
lib/lp/app/templates/root-index.pt (+1/-1)
lib/lp/bugs/stories/guided-filebug/xx-bug-reporting-tools.txt (+10/-6)
lib/lp/bugs/stories/guided-filebug/xx-ubuntu-filebug.txt (+8/-0)
lib/lp/services/webapp/adapter.py (+3/-3)
lib/lp/services/webapp/errorlog.py (+8/-10)
lib/lp/services/webapp/tests/test_user_requested_oops.py (+19/-12)
lib/lp/soyuz/stories/soyuz/xx-builder-page.txt (+4/-1)
lib/lp/soyuz/stories/soyuz/xx-buildfarm-index.txt (+2/-0)
lib/lp/soyuz/stories/soyuz/xx-builds-pages.txt (+2/-1)
lib/lp/soyuz/stories/soyuz/xx-private-builds.txt (+5/-1)
lib/lp/translations/stories/buildfarm/xx-build-summary.txt (+1/-0)
To merge this branch: bzr merge lp:~wgrant/launchpad/html-wtf
Reviewer Review Type Date Requested Status
Steve Kowalik (community) code 2012-03-06 Approve on 2012-03-07
Review via email: mp+96265@code.launchpad.net

Commit Message

[r=stevenk][no-qa] Fix various bits of invalid HTML in the base template.

Description of the Change

This branch fixes some invalid HTML in the base template, with a convenient improvement as fallout.

 - Fixed the size attribute of the front page search box from "25%" to "25", since it's not a percentage. Browsers just ignored the %.
 - Removed the empty <noscript> from base-layout.pt. This was invalid markup which caused mechanise to fail to detect <meta http-equiv="Refresh"> elements, so two apport bug filing tests needed adjusting to prevent the redirect.
 - Fixed the HTML for the debug timeline, and moved the conditional up a level to stop the anchor from being rendered even when the timeline was not meant to be shown.
 - Made the debug timeline valid by moving it into the body. This brought it up to before the summarize_requests comment, causing the UserRequestOops ID to never show up in the comment. I adjusted the UserRequestOops code to function correctly when called multiple times, which has the handy side-effect of showing the OOPS ID in the visible_render_time.

To post a comment you must log in.
Steve Kowalik (stevenk) wrote :

Aside from the disgusting use of structure() in tal:replace thanks to IE (but it isn't your fault), this looks great.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/app/templates/base-layout-macros.pt'
2--- lib/lp/app/templates/base-layout-macros.pt 2012-02-15 22:09:43 +0000
3+++ lib/lp/app/templates/base-layout-macros.pt 2012-03-07 10:24:27 +0000
4@@ -474,25 +474,24 @@
5
6
7 <metal:debug-timeline define-macro="debug-timeline">
8- <a name="debug_timeline"
9- id="debug_timeline"
10- class="hidden"
11- >
12- <table
13- tal:condition="request/features/visible_render_time"
14- tal:define="timeline_actions modules/lp.services.webapp.adapter/get_timeline_actions"
15- class="debug-timeline listing"
16- >
17+ <a tal:condition="request/features/visible_render_time"
18+ tal:define="timeline_actions modules/lp.services.webapp.adapter/get_timeline_actions"
19+ id="debug_timeline" class="hidden">
20+ <table class="debug-timeline listing">
21 <thead>
22- <th>Duration</th>
23- <th>Action</th>
24+ <tr>
25+ <th>Duration</th>
26+ <th>Action</th>
27+ </tr>
28 </thead>
29- <tr tal:repeat="action timeline_actions">
30- <td class="amount" tal:content="action/duration/fmt:millisecondduration"/>
31- <td style="font-family: monospace; text-align: left;">
32- <pre class="wrap"><span class="action-category" tal:content="action/category"/>: <span class="action-details" tal:content="action/detail"/></pre>
33- </td>
34- </tr>
35+ <tbody>
36+ <tr tal:repeat="action timeline_actions">
37+ <td class="amount" tal:content="action/duration/fmt:millisecondduration"/>
38+ <td style="font-family: monospace; text-align: left;">
39+ <pre class="wrap"><span class="action-category" tal:content="action/category"/>: <span class="action-details" tal:content="action/detail"/></pre>
40+ </td>
41+ </tr>
42+ </tbody>
43 </table>
44 </a>
45 </metal:debug-timeline>
46
47=== modified file 'lib/lp/app/templates/base-layout.pt'
48--- lib/lp/app/templates/base-layout.pt 2012-02-24 04:54:53 +0000
49+++ lib/lp/app/templates/base-layout.pt 2012-03-07 10:24:27 +0000
50@@ -43,15 +43,6 @@
51 html, body {background-image: url(/@@/demo) !important;}
52 </style>
53
54- <tal:comment condition="nothing">
55- Removing the below <noscript></noscript> snippet makes two tests fail
56- with redirection problems:
57- xx-ubuntu-filebug.txt
58- xx-bug-reporting-tools.txt
59- No time to look into it now, so keeping it in. XXX Danilo 20110715
60- </tal:comment>
61- <noscript></noscript>
62-
63 <tal:view condition="not: view/macro:is-page-contentless">
64 <meta name="description"
65 tal:condition="view/page_description | nothing"
66@@ -176,6 +167,21 @@
67
68 <metal:lp-client-cache
69 use-macro="context/@@+base-layout-macros/lp-client-cache" />
70+ <metal:debug-timeline
71+ use-macro="context/@@+base-layout-macros/debug-timeline" />
72+ <tal:comment
73+ tal:condition="request/features/visible_render_time"
74+ define="render_time modules/lp.services.webapp.adapter/summarize_requests;"
75+ replace='structure string:&lt;script type="text/javascript"&gt;
76+ var render_time = "${render_time}";
77+ LPJS.use("node", "lp.ajax_log" , function(Y) {
78+ Y.on("domready", function() {
79+ var node = Y.one("#rendertime");
80+ node.set("innerHTML", render_time);
81+ var ajax_log = new Y.lp.ajax_log();
82+ });
83+ });
84+ &lt;/script&gt;' />
85 </body>
86
87 <tal:template>
88@@ -196,24 +202,5 @@
89
90 --&gt;" />
91 </tal:template>
92-
93-
94-<metal:debug-timeline
95- use-macro="context/@@+base-layout-macros/debug-timeline" />
96-
97-<tal:comment
98- tal:condition="request/features/visible_render_time"
99- define="render_time modules/lp.services.webapp.adapter/summarize_requests;"
100- replace='structure string:&lt;script type="text/javascript"&gt;
101- var render_time = "${render_time}";
102- LPJS.use("node", "lp.ajax_log" , function(Y) {
103- Y.on("domready", function() {
104- var node = Y.one("#rendertime");
105- node.set("innerHTML", render_time);
106- var ajax_log = new Y.lp.ajax_log();
107- });
108- });
109-&lt;/script&gt;' />
110-
111 </html>
112 </metal:page>
113
114=== modified file 'lib/lp/app/templates/root-index.pt'
115--- lib/lp/app/templates/root-index.pt 2012-02-24 04:44:55 +0000
116+++ lib/lp/app/templates/root-index.pt 2012-03-07 10:24:27 +0000
117@@ -136,7 +136,7 @@
118 xml:lang="en" lang="en" dir="ltr"
119 tal:attributes="action string:${rooturl}+search"
120 method="get" accept-charset="UTF-8">
121- <input id="text" type="text" name="field.text" size="25%" />
122+ <input id="text" type="text" name="field.text" size="25" />
123 <input id="search" type="submit" value="Search Launchpad" />
124 </form>
125 <script type="text/javascript">
126
127=== modified file 'lib/lp/bugs/stories/guided-filebug/xx-bug-reporting-tools.txt'
128--- lib/lp/bugs/stories/guided-filebug/xx-bug-reporting-tools.txt 2011-12-29 05:29:36 +0000
129+++ lib/lp/bugs/stories/guided-filebug/xx-bug-reporting-tools.txt 2012-03-07 10:24:27 +0000
130@@ -61,22 +61,26 @@
131 The most common case will be that the user is sent to the guided
132 +filebug page and the user goes through the workflow there.
133
134- >>> filebug_url = (
135- ... 'http://launchpad.dev/ubuntu/+source/mozilla-firefox/+filebug/'
136- ... '%s' % blob_token)
137- >>> user_browser.open(filebug_url)
138+ >>> filebug_host = 'launchpad.dev'
139+ >>> filebug_path = (
140+ ... '/ubuntu/+source/mozilla-firefox/+filebug/%s' % blob_token)
141+ >>> filebug_url = 'http://%s%s' % (filebug_host, filebug_path)
142+ >>> contents = str(http(
143+ ... "GET %s HTTP/1.1\nHostname: %s\n"
144+ ... "Authorization: Basic test@canonical.com:test\n\n"
145+ ... % (filebug_path, filebug_host)))
146
147 At first, the user will be shown a message telling them that the extra
148 data is being processed.
149
150- >>> for message in find_tags_by_class(user_browser.contents, 'message'):
151+ >>> for message in find_tags_by_class(contents, 'message'):
152 ... print message.renderContents()
153 Please wait while bug data is processed. This page will refresh
154 every 10 seconds until processing is complete.
155
156 The page header contains a 10-second meta refresh tag.
157
158- >>> '<meta http-equiv="refresh" content="10"' in user_browser.contents
159+ >>> '<meta http-equiv="refresh" content="10"' in contents
160 True
161
162 Once the data has been processed, the +filebug process can continue as
163
164=== modified file 'lib/lp/bugs/stories/guided-filebug/xx-ubuntu-filebug.txt'
165--- lib/lp/bugs/stories/guided-filebug/xx-ubuntu-filebug.txt 2011-12-29 05:29:36 +0000
166+++ lib/lp/bugs/stories/guided-filebug/xx-ubuntu-filebug.txt 2012-03-07 10:24:27 +0000
167@@ -71,6 +71,14 @@
168 ... extra_filebug_data, 'not/important', 'not.important')
169 >>> anon_browser.getControl(name='FORM_SUBMIT').click()
170 >>> blob_token = anon_browser.headers['X-Launchpad-Blob-Token']
171+ >>> from lp.bugs.interfaces.apportjob import IProcessApportBlobJobSource
172+ >>> login('foo.bar@canonical.com')
173+ >>> job = getUtility(IProcessApportBlobJobSource).getByBlobUUID(
174+ ... blob_token)
175+ >>> job.job.start()
176+ >>> job.run()
177+ >>> job.job.complete()
178+ >>> logout()
179 >>> filebug_url = (
180 ... 'http://launchpad.dev/ubuntu/+source/mozilla-firefox/+filebug/'
181 ... '%s' % blob_token)
182
183=== modified file 'lib/lp/services/webapp/adapter.py'
184--- lib/lp/services/webapp/adapter.py 2011-12-30 08:13:14 +0000
185+++ lib/lp/services/webapp/adapter.py 2012-03-07 10:24:27 +0000
186@@ -226,11 +226,11 @@
187 timeline = get_request_timeline(request)
188 from lp.services.webapp.errorlog import (
189 maybe_record_user_requested_oops)
190- oopsid = maybe_record_user_requested_oops()
191- if oopsid is None:
192+ maybe_record_user_requested_oops()
193+ if request.oopsid is None:
194 oops_str = ""
195 else:
196- oops_str = " %s" % oopsid
197+ oops_str = " %s" % request.oopsid
198 log = "%s queries/external actions issued in %.2f seconds%s" % (
199 len(timeline.actions), secs, oops_str)
200 return log
201
202=== modified file 'lib/lp/services/webapp/errorlog.py'
203--- lib/lp/services/webapp/errorlog.py 2012-01-01 02:58:52 +0000
204+++ lib/lp/services/webapp/errorlog.py 2012-03-07 10:24:27 +0000
205@@ -542,18 +542,16 @@
206 def maybe_record_user_requested_oops():
207 """If an OOPS has been requested, report one.
208
209- :return: The oopsid of the requested oops. Returns None if an oops was
210- not requested, or if there is already an OOPS.
211+ It will be stored in request.oopsid.
212 """
213 request = get_current_browser_request()
214- # If there is no request, or there is an oops already, then return.
215- if (request is None or
216- request.oopsid is not None or
217- not request.annotations.get(LAZR_OOPS_USER_REQUESTED_KEY, False)):
218- return None
219- globalErrorUtility.raising(
220- (UserRequestOops, UserRequestOops(), None), request)
221- return request.oopsid
222+ # If there's a request and no existing OOPS, but an OOPS has been
223+ # requested, record one.
224+ if (request is not None
225+ and request.oopsid is None
226+ and request.annotations.get(LAZR_OOPS_USER_REQUESTED_KEY, False)):
227+ globalErrorUtility.raising(
228+ (UserRequestOops, UserRequestOops(), None), request)
229
230
231 class OopsNamespace(view):
232
233=== modified file 'lib/lp/services/webapp/tests/test_user_requested_oops.py'
234--- lib/lp/services/webapp/tests/test_user_requested_oops.py 2012-01-01 02:58:52 +0000
235+++ lib/lp/services/webapp/tests/test_user_requested_oops.py 2012-03-07 10:24:27 +0000
236@@ -37,20 +37,28 @@
237 def test_none_requested(self):
238 # If an oops was not requested, then maybe_record_user_requested_oops
239 # does not record an oops.
240- oops_id = maybe_record_user_requested_oops()
241- self.assertIs(None, oops_id)
242 request = get_current_browser_request()
243+ maybe_record_user_requested_oops()
244 self.assertIs(None, request.oopsid)
245
246 def test_annotation_key(self):
247- # The request for an oops is stored in the request annotations. If a
248- # user request oops is recorded, the oops id is returned, and also
249- # stored in the request.
250- request = get_current_browser_request()
251- request.annotations[LAZR_OOPS_USER_REQUESTED_KEY] = True
252- oops_id = maybe_record_user_requested_oops()
253- self.assertIsNot(None, oops_id)
254- self.assertEqual(oops_id, request.oopsid)
255+ # The request for an oops is stored in the request annotations.
256+ # If a user request oops is recorded, the oops id is stored in
257+ # the request.
258+ request = get_current_browser_request()
259+ request.annotations[LAZR_OOPS_USER_REQUESTED_KEY] = True
260+ self.assertIs(None, request.oopsid)
261+ maybe_record_user_requested_oops()
262+ self.assertIsNot(None, request.oopsid)
263+
264+ def test_multiple_calls(self):
265+ # Asking to record the OOPS twice just returns the same ID.
266+ request = get_current_browser_request()
267+ request.annotations[LAZR_OOPS_USER_REQUESTED_KEY] = True
268+ maybe_record_user_requested_oops()
269+ orig_oops_id = request.oopsid
270+ maybe_record_user_requested_oops()
271+ self.assertEqual(orig_oops_id, request.oopsid)
272
273 def test_existing_oops_stops_user_requested(self):
274 # If there is already an existing oops id in the request, then the
275@@ -58,8 +66,7 @@
276 request = get_current_browser_request()
277 request.oopsid = "EXISTING"
278 request.annotations[LAZR_OOPS_USER_REQUESTED_KEY] = True
279- oops_id = maybe_record_user_requested_oops()
280- self.assertIs(None, oops_id)
281+ maybe_record_user_requested_oops()
282 self.assertEqual("EXISTING", request.oopsid)
283
284 def test_OopsNamespace_traverse(self):
285
286=== modified file 'lib/lp/soyuz/stories/soyuz/xx-builder-page.txt'
287--- lib/lp/soyuz/stories/soyuz/xx-builder-page.txt 2012-01-15 11:06:57 +0000
288+++ lib/lp/soyuz/stories/soyuz/xx-builder-page.txt 2012-03-07 10:24:27 +0000
289@@ -4,6 +4,7 @@
290 builder state. In the sampledata, the builder 'bob' is building
291 'mozilla-firefox'.
292
293+ >>> anon_browser.mech_browser.set_handle_equiv(False)
294 >>> anon_browser.open("http://launchpad.dev/builders")
295 >>> anon_browser.getLink("bob").click()
296
297@@ -27,6 +28,7 @@
298 timezone. This way they can easily find out if they are reading
299 outdated information.
300
301+ >>> user_browser.mech_browser.set_handle_equiv(False)
302 >>> user_browser.open(anon_browser.url)
303 >>> print extract_text(find_portlet(
304 ... user_browser.contents, 'View full history Current status'))
305@@ -68,6 +70,7 @@
306
307 >>> cprov_browser = setupBrowser(
308 ... auth='Basic celso.providelo@canonical.com:test')
309+ >>> cprov_browser.mech_browser.set_handle_equiv(False)
310
311 >>> cprov_browser.open('http://launchpad.dev/builders')
312 >>> cprov_browser.getLink('bob').click()
313@@ -193,7 +196,7 @@
314 when they judge it convenient, for instance, when the builder present
315 transient failures or is used for another purpose.
316
317- >>> cprov_browser.open('http://launchpad.dev/+builds')
318+ >>> cprov_browser.open('http://launchpad.dev/builders')
319 >>> cprov_browser.getLink('bob').click()
320 >>> print backslashreplace(cprov_browser.title)
321 Bob The Builder : Build Farm
322
323=== modified file 'lib/lp/soyuz/stories/soyuz/xx-buildfarm-index.txt'
324--- lib/lp/soyuz/stories/soyuz/xx-buildfarm-index.txt 2011-12-23 23:44:59 +0000
325+++ lib/lp/soyuz/stories/soyuz/xx-buildfarm-index.txt 2012-03-07 10:24:27 +0000
326@@ -4,6 +4,7 @@
327 link to it yet because we are not yet sure of the benefits of doing
328 this, since the audience of this page is still restricted.
329
330+ >>> anon_browser.mech_browser.set_handle_equiv(False)
331 >>> anon_browser.open('http://launchpad.dev/+builds')
332
333 The BuildFarm contains a list of all builders registered in Launchpad
334@@ -120,6 +121,7 @@
335
336 Administrators can create new builders.
337
338+ >>> admin_browser.mech_browser.set_handle_equiv(False)
339 >>> admin_browser.open("http://launchpad.dev/+builds/+index")
340
341 >>> admin_browser.getLink("Register a new build machine").click()
342
343=== modified file 'lib/lp/soyuz/stories/soyuz/xx-builds-pages.txt'
344--- lib/lp/soyuz/stories/soyuz/xx-builds-pages.txt 2012-01-06 11:08:30 +0000
345+++ lib/lp/soyuz/stories/soyuz/xx-builds-pages.txt 2012-03-07 10:24:27 +0000
346@@ -69,7 +69,8 @@
347
348 For Builder, same as Distribution:
349
350- >>> anon_browser.open("http://launchpad.dev/+builds/bob")
351+ >>> anon_browser.mech_browser.set_handle_equiv(False)
352+ >>> anon_browser.open("http://launchpad.dev/builders/bob")
353 >>> anon_browser.getLink("View full history").click()
354 >>> print anon_browser.title
355 Build history : Bob The Builder : Build Farm
356
357=== modified file 'lib/lp/soyuz/stories/soyuz/xx-private-builds.txt'
358--- lib/lp/soyuz/stories/soyuz/xx-private-builds.txt 2012-01-15 11:06:57 +0000
359+++ lib/lp/soyuz/stories/soyuz/xx-private-builds.txt 2012-03-07 10:24:27 +0000
360@@ -65,6 +65,7 @@
361 The status shown to an anonymous user hides the private source it is
362 building.
363
364+ >>> anon_browser.mech_browser.set_handle_equiv(False)
365 >>> anon_browser.open("http://launchpad.dev/+builds/frog")
366 >>> print extract_text(find_main_content(anon_browser.contents))
367 The frog builder...
368@@ -74,6 +75,7 @@
369
370 Launchpad Administrators are allowed to see the build:
371
372+ >>> admin_browser.mech_browser.set_handle_equiv(False)
373 >>> admin_browser.open("http://launchpad.dev/+builds/frog")
374 >>> print extract_text(find_main_content(admin_browser.contents))
375 The frog builder...
376@@ -85,6 +87,7 @@
377 Buildd Administrators are not allowed to see the build in the portlet:
378
379 >>> name12_browser = setupBrowser(auth="Basic test@canonical.com:test")
380+ >>> name12_browser.mech_browser.set_handle_equiv(False)
381 >>> name12_browser.open("http://launchpad.dev/+builds/frog")
382 >>> print extract_text(find_main_content(name12_browser.contents))
383 The frog builder...
384@@ -96,6 +99,7 @@
385
386 >>> cprov_browser = setupBrowser(
387 ... auth="Basic celso.providelo@canonical.com:test")
388+ >>> cprov_browser.mech_browser.set_handle_equiv(False)
389 >>> cprov_browser.open("http://launchpad.dev/+builds/frog")
390 >>> print extract_text(find_main_content(cprov_browser.contents))
391 The frog builder...
392@@ -295,7 +299,6 @@
393
394 Now the anonymous user can see the build:
395
396- >>> anon_browser = setupBrowser()
397 >>> anon_browser.open("http://launchpad.dev/+builds")
398 >>> print extract_text(find_main_content(anon_browser.contents))
399 The Launchpad build farm
400@@ -307,6 +310,7 @@
401
402 Any other logged-in user will also see the build:
403
404+ >>> browser.mech_browser.set_handle_equiv(False)
405 >>> browser.open("http://launchpad.dev/+builds")
406 >>> print extract_text(find_main_content(browser.contents))
407 The Launchpad build farm
408
409=== modified file 'lib/lp/translations/stories/buildfarm/xx-build-summary.txt'
410--- lib/lp/translations/stories/buildfarm/xx-build-summary.txt 2012-02-09 23:09:36 +0000
411+++ lib/lp/translations/stories/buildfarm/xx-build-summary.txt 2012-03-07 10:24:27 +0000
412@@ -71,6 +71,7 @@
413 The job's summary shows that what type of job this is. It also links
414 to the branch.
415
416+ >>> user_browser.mech_browser.set_handle_equiv(False)
417 >>> user_browser.open(builder_page)
418 >>> print extract_text(find_build_summary(user_browser))
419 Working on TranslationTemplatesBuildJob for branch ...