Merge lp:~allenap/launchpad/ui-convert-bug-activity-bug-412523 into lp:launchpad

Proposed by Gavin Panella
Status: Merged
Approved by: Gavin Panella
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~allenap/launchpad/ui-convert-bug-activity-bug-412523
Merge into: lp:launchpad
Diff against target: None lines
To merge this branch: bzr merge lp:~allenap/launchpad/ui-convert-bug-activity-bug-412523
Reviewer Review Type Date Requested Status
Celso Providelo (community) code Approve
Michael Nelson (community) ui Approve
Martin Albisetti Pending
Review via email: mp+10026@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Gavin Panella (allenap) wrote :

This branch converts bug-activity.pt to the new 3.0 base template according to the instructions at <https://dev.launchpad.net/VersionThreeDotO/UI/Conversion>. I am expecting to have to make more changes arising from this review, but that's what I want: it is the first bugs template to be converted, so it's also so I can figure out the process. Once I understand it better I will split up the work so the whole team can get to work on it.

I have before and after screenshots (also linked from the bug report):

  http://launchpadlibrarian.net/30223879/before-mechanical-changes.png

  http://launchpadlibrarian.net/30223898/after-mechanical-changes.png

My comments on the changes so far, taken from <https://bugs.edge.launchpad.net/malone/+bug/412523/comments/3>:

> The changes so far have been almost exclusively mechanical. I've
> chosen the main_only base template, and tried to apply the CSS
> rules. I can see the following issues with the new page:
>
> * "Mozilla Firefox" is repeated in the breadcrumbs and in the
> location-portlet.
>
> * The bug activity log has always been shown in bugtask
> context. The new application tabs block is much more prominent
> than the old and looks a bit daft in the activity log which is
> bug-related, not bugtask related.
>
>
> * Repetition of "bug #1" close together.
>
> * The table border butts against the divider at the bottom of the
> page, and creates the appearance of a double thickness border. A
> margin-bottom on that table would fix it, but that smells a
> but. Is there already a way to handle this "nicely"?

Test: ./bin/test -vvt xx-bug-activity

Lint free.

Revision history for this message
Michael Nelson (michael.nelson) wrote :
Download full text (7.2 KiB)

Hi Gavin,

Great start! It's a nice simple informational page without actions so a good one to begin with!

I've marked it as needs fixing, just to sort out the portlet divs etc.

> This branch converts bug-activity.pt to the new 3.0 base template according to
> the instructions at
> <https://dev.launchpad.net/VersionThreeDotO/UI/Conversion>. I am expecting to
> have to make more changes arising from this review, but that's what I want: it
> is the first bugs template to be converted, so it's also so I can figure out
> the process. Once I understand it better I will split up the work so the whole
> team can get to work on it.

Great idea!

>
> I have before and after screenshots (also linked from the bug report):
>
> http://launchpadlibrarian.net/30223879/before-mechanical-changes.png
>
> http://launchpadlibrarian.net/30223898/after-mechanical-changes.png

Thanks for that! So much easier... and great to enable discussion on the bug too!

I'll respond to your thoughts below, and then summarise more generally at the bottom...

>
> My comments on the changes so far, taken from
> <https://bugs.edge.launchpad.net/malone/+bug/412523/comments/3>:
>
> > The changes so far have been almost exclusively mechanical. I've
> > chosen the main_only base template, and tried to apply the CSS
> > rules. I can see the following issues with the new page:
> >
> > * "Mozilla Firefox" is repeated in the breadcrumbs and in the
> > location-portlet.

The breadcrumbs will be moving to directly below your h1 heading, and will be less prominent. I personally don't see the repetition as a problem in the context of breadcrumbs (ie. they will always display the path of your traversal by necessity).

> >
> > * The bug activity log has always been shown in bugtask
> > context. The new application tabs block is much more prominent
> > than the old and looks a bit daft in the activity log which is
> > bug-related, not bugtask related.

Hmmm... But the application tabs block is showing the user the related pillar-or-person - in this case the product. So I'm not sure why you think it's confusing in either bug/bugtask context? But I'm not sure I've properly understood your point here.

> >
> >
> > * Repetition of "bug #1" close together.

Yes, but as we chatted, I really think that 'bug #1' link should be part of the breadcrumb...

Firefox > Bug #1

Perhaps you should chat with salgado and find out if it will indeed be included in the new breadcrumb (or if he can ensure that it is). In which case, I'd be for removing it.

> >
> > * The table border butts against the divider at the bottom of the
> > page, and creates the appearance of a double thickness border. A
> > margin-bottom on that table would fix it, but that smells a
> > but. Is there already a way to handle this "nicely"?

I think this is just because you don't have the table in a portlet div. You seem to have just the top-portlet which has the link.

I think you should either have one single top-portlet (my preference), or if you need to leave the link in and you think it should be in a separate portlet, then you'd need to wrap your table in a portlet div too, but I really think you hav...

Read more...

review: Needs Fixing (ui)
Revision history for this message
Gavin Panella (allenap) wrote :

Thanks for the review Michael!

I've add a BugTask breadcrumb, that just says "Bug #X", and tests in
lp/bugs/test/test_breadcrumbs.py which is ripped off from salgado's
work on breadcrumbs.

> > > * The table border butts against the divider at the bottom of the
> > > page, and creates the appearance of a double thickness border. A
> > > margin-bottom on that table would fix it, but that smells a
> > > but. Is there already a way to handle this "nicely"?
>
> I think this is just because you don't have the table in a portlet div. You
> seem to have just the top-portlet which has the link.
>
> I think you should either have one single top-portlet (my preference), or if
> you need to leave the link in and you think it should be in a separate
> portlet, then you'd need to wrap your table in a portlet div too, but I really
> think you have just one piece of information on that page (the activity log).

I've added a single top-portlet div.

> So, other general thoughts:
> * The date formatting (which beuno mentioned)

Fixed, though I'm not using fmt:datetime because of bug 412963
(fmt:datetime displays date and time in current timezone, even when
UTC only is desired). I've added an XXX to the template.

> * Assuming the breadcrumb will include Bug #1, would it make sense to update
> the H1 to instead include the name of the bug rather than the number (or in
> addition to)?

Yes, the bug title is now in the heading.

> * Given that this page is traversable by other products (and the activity is
> related to other products as you said), I'd expect to see "Other related
> products" or something on this page, when there are some. I realise this
> wouldn't be part of the mechanical update, but it would be great to do. At
> least an XXX for a bug?

This is a weird one. The presence of the product heading doesn't
always make sense at first on the activity log page (or many other
pages that are found below the bug page). Once the breadcrumbs are
moved to below the product heading it will make a bit more sense. But
I'm not sure what value there is in drawing attention to the fact that
this activity log page can be seen in the context of another product;
the main page content will be identical. This is definitely something
the bugs team are going to have to talk about as part of our 3.0
redesign.

I've attached a couple of diffs showing the changes I've made. I had
to merge devel in the middle of my changes because the tree would no
longer build (and the bin/buildout workaround was also not working), I
made some whitespace changes, and I also fixed some lint, none of
which is interesting here.

=== modified file 'lib/lp/bugs/browser/bugtask.py'
--- lib/lp/bugs/browser/bugtask.py 2009-08-07 23:20:33 +0000
+++ lib/lp/bugs/browser/bugtask.py 2009-08-13 10:14:48 +0000
@@ -14,6 +14,7 @@
14 'BugTargetView',14 'BugTargetView',
15 'BugTaskContextMenu',15 'BugTaskContextMenu',
16 'BugTaskCreateQuestionView',16 'BugTaskCreateQuestionView',
17 'BugTaskBreadcrumbBuilder',
17 'BugTaskEditView',18 'BugTaskEditView',
18 'BugTaskExpirableListingView',19 'BugTaskExpirableListingView',
19 'BugTaskListingItem',20 'BugTaskListingItem',
@@ -116,6 +117,7 @@
116from lp.registry.interfaces.sourcepackage import ISourcePackage117from lp.registry.interfaces.sourcepackage import ISourcePackage
117from canonical.launchpad.interfaces.validation import (118from canonical.launchpad.interfaces.validation import (
118 valid_upstreamtask, validate_distrotask)119 valid_upstreamtask, validate_distrotask)
120from canonical.launchpad.webapp.breadcrumb import BreadcrumbBuilder
119from canonical.launchpad.webapp.interfaces import (121from canonical.launchpad.webapp.interfaces import (
120 ILaunchBag, NotFoundError, UnexpectedFormData)122 ILaunchBag, NotFoundError, UnexpectedFormData)
121123
@@ -3476,3 +3478,12 @@
3476 return_dict[key] = cgi.escape(return_dict[key])3478 return_dict[key] = cgi.escape(return_dict[key])
34773479
3478 return "%(old_value)s &#8594; %(new_value)s" % return_dict3480 return "%(old_value)s &#8594; %(new_value)s" % return_dict
3481
3482
3483class BugTaskBreadcrumbBuilder(BreadcrumbBuilder):
3484 """Builds a breadcrumb for an `IBugTask`."""
3485 @property
3486 def text(self):
3487 return "%s: %s" % (
3488 self.context.bug.displayname,
3489 self.context.bug.title)
34793490
=== modified file 'lib/lp/bugs/configure.zcml'
--- lib/lp/bugs/configure.zcml 2009-07-23 13:44:13 +0000
+++ lib/lp/bugs/configure.zcml 2009-08-13 10:14:48 +0000
@@ -263,6 +263,12 @@
263 <adapter263 <adapter
264 factory="lp.bugs.browser.bugtask.assignee_renderer"264 factory="lp.bugs.browser.bugtask.assignee_renderer"
265 name="assignee"/>265 name="assignee"/>
266 <adapter
267 provides="canonical.launchpad.webapp.interfaces.IBreadcrumbBuilder"
268 for="lp.bugs.interfaces.bugtask.IBugTask"
269 factory="lp.bugs.browser.bugtask.BugTaskBreadcrumbBuilder"
270 permission="zope.Public"/>
271
266 272
267 <!-- NullBugTask -->273 <!-- NullBugTask -->
268 274
269275
=== modified file 'lib/lp/bugs/templates/bug-activity.pt'
--- lib/lp/bugs/templates/bug-activity.pt 2009-08-12 13:02:26 +0000
+++ lib/lp/bugs/templates/bug-activity.pt 2009-08-13 10:14:13 +0000
@@ -10,10 +10,8 @@
10 </div>10 </div>
1111
12 <div metal:fill-slot="main">12 <div metal:fill-slot="main">
13 <div class="yui-g">
13 <div class="top-portlet">14 <div class="top-portlet">
14 <p tal:content="structure context/fmt:link" />
15 </div>
16 <div class="yui-g">
17 <table class="listing">15 <table class="listing">
18 <thead>16 <thead>
19 <tr>17 <tr>
@@ -39,5 +37,6 @@
39 </tbody>37 </tbody>
40 </table>38 </table>
41 </div>39 </div>
40 </div>
42 </div>41 </div>
43</bug-activity>42</bug-activity>
=== modified file 'lib/lp/bugs/browser/bugtask.py'
--- lib/lp/bugs/browser/bugtask.py 2009-08-13 10:15:14 +0000
+++ lib/lp/bugs/browser/bugtask.py 2009-08-13 12:41:32 +0000
@@ -3498,6 +3498,4 @@
3498 """Builds a breadcrumb for an `IBugTask`."""3498 """Builds a breadcrumb for an `IBugTask`."""
3499 @property3499 @property
3500 def text(self):3500 def text(self):
3501 return "%s: %s" % (3501 return self.context.bug.displayname
3502 self.context.bug.displayname,
3503 self.context.bug.title)
35043502
=== modified file 'lib/lp/bugs/stories/bugs/xx-bug-activity.txt'
--- lib/lp/bugs/stories/bugs/xx-bug-activity.txt 2009-08-06 13:51:38 +0000
+++ lib/lp/bugs/stories/bugs/xx-bug-activity.txt 2009-08-13 12:59:41 +0000
@@ -7,16 +7,19 @@
7 ... 'mozilla-firefox/+bug/3/+activity')7 ... 'mozilla-firefox/+bug/3/+activity')
8 >>> main_content = find_main_content(anon_browser.contents)8 >>> main_content = find_main_content(anon_browser.contents)
99
10The page heading contains a link back to the bug page.10The page contains a link back to the bug page:
1111
12 >>> bug_link = main_content.p.a12 >>> document = find_tag_by_id(anon_browser.contents, 'document')
13 >>> print '%s --> %s' % (extract_text(bug_link), bug_link['href'])13 >>> bug_link = document.find(
14 Bug #3: Bug Title Test --> /debian/+source/mozilla-firefox/+bug/314 ... 'a', href=lambda href: href.endswith('/+bug/3'))
15 >>> print '%s\n--> %s' % (extract_text(bug_link), bug_link['href'])
16 Bug #3
17 --> http://bugs.launchpad.dev/debian/+source/mozilla-firefox/+bug/3
1518
16The title repeats the bug number for clarity.19The title repeats the bug number for clarity.
1720
18 >>> print extract_text(main_content.h1)21 >>> print extract_text(main_content.h1)
19 Activity log for bug #322 Activity log for bug #3 - Bug Title Test
2023
21The activity log itself is presented as a table.24The activity log itself is presented as a table.
2225
@@ -27,9 +30,9 @@
27 >>> for row in main_content.table('tr'):30 >>> for row in main_content.table('tr'):
28 ... print_row(row)31 ... print_row(row)
29 Date | Who | What changed | Old value | New value | Message32 Date | Who | What changed | Old value | New value | Message
30 10 Aug 05 16:30 | Sample Person | bug | | | assigned to source ...33 2005-08-10 16:30:32 | Sample Person | bug | | | assigned to source ...
31 10 Aug 05 16:30 | Sample Person | bug | | | assigned to source ...34 2005-08-10 16:30:47 | Sample Person | bug | | | assigned to source ...
32 24 Feb 06 21:34 | Foo Bar | mozilla-firefox: statusexplanation | | |35 2006-02-24 21:34:52 | Foo Bar | mozilla-firefox: statusexplanation | | |
3336
3437
35== Activity interleaved with comments ==38== Activity interleaved with comments ==
3639
=== modified file 'lib/lp/bugs/templates/bug-activity.pt'
--- lib/lp/bugs/templates/bug-activity.pt 2009-08-13 10:14:13 +0000
+++ lib/lp/bugs/templates/bug-activity.pt 2009-08-13 12:59:41 +0000
@@ -6,7 +6,10 @@
6 metal:use-macro="view/macro:page/main_only">6 metal:use-macro="view/macro:page/main_only">
77
8 <div metal:fill-slot="heading">8 <div metal:fill-slot="heading">
9 <h1>Activity log for bug #<span tal:replace="context/bug/id" /></h1>9 <h1>
10 Activity log for bug #<span tal:replace="context/bug/id" /> -
11 <span tal:replace="context/bug/title" />
12 </h1>
10 </div>13 </div>
1114
12 <div metal:fill-slot="main">15 <div metal:fill-slot="main">
@@ -25,8 +28,13 @@
25 </thead>28 </thead>
26 <tbody>29 <tbody>
27 <tr tal:repeat="log context/bug/activity">30 <tr tal:repeat="log context/bug/activity">
28 <td tal:content="python:log.datechanged.strftime('%d %b %y %H:%M')">31 <tal:comment condition="nothing">
29 13 Sep 04 14:1532 XXX: Gavin Panella 2009-08-12 bug=412963: Using strftime()
33 here because fmt:datetime changes timezone, even though we
34 always want to show only UTC.
35 </tal:comment>
36 <td tal:content="python:log.datechanged.strftime('%Y-%m-%d %T')">
37 2004-09-24 12:04:43
30 </td>38 </td>
31 <td><tal:person tal:replace="structure log/person/fmt:link">person</tal:person></td>39 <td><tal:person tal:replace="structure log/person/fmt:link">person</tal:person></td>
32 <td tal:content="log/whatchanged">description</td>40 <td tal:content="log/whatchanged">description</td>
3341
=== added file 'lib/lp/bugs/tests/test_breadcrumbs.py'
--- lib/lp/bugs/tests/test_breadcrumbs.py 1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/tests/test_breadcrumbs.py 2009-08-13 13:57:47 +0000
@@ -0,0 +1,71 @@
1# Copyright 2009 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4__metaclass__ = type
5
6import unittest
7
8from zope.component import getMultiAdapter
9
10from canonical.lazr.testing.menus import make_fake_request
11from canonical.launchpad.webapp.publisher import RootObject
12from canonical.testing import DatabaseFunctionalLayer
13from lp.testing import TestCaseWithFactory
14
15
16class TestBugTaskBreadcrumbBuilder(TestCaseWithFactory):
17
18 layer = DatabaseFunctionalLayer
19
20 def setUp(self):
21 TestCaseWithFactory.setUp(self)
22 self.product = self.factory.makeProduct(
23 name='crumb-tester', displayname="Crumb Tester")
24 self.bug = self.factory.makeBug(product=self.product)
25 self.root = RootObject()
26
27 def test_bugtask_on_mainsite(self):
28 request = make_fake_request(
29 'http://launchpad.dev/%s/+bug/%d' % (
30 self.product.name, self.bug.id),
31 [self.root, self.product, self.bug.default_bugtask])
32 hierarchy = getMultiAdapter((self.root, request), name='+hierarchy')
33 self.assertEquals(
34 ['http://launchpad.dev/crumb-tester',
35 'http://launchpad.dev/crumb-tester/+bug/%d' % self.bug.id],
36 [crumb.url for crumb in hierarchy.items()])
37 self.assertEquals(
38 ["Crumb Tester", "Bug #%d" % self.bug.id],
39 [crumb.text for crumb in hierarchy.items()])
40
41 def test_bugtask_on_vhost(self):
42 request = make_fake_request(
43 'http://bugs.launchpad.dev/%s/+bug/%d' % (
44 self.product.name, self.bug.id),
45 [self.root, self.product, self.bug.default_bugtask])
46 hierarchy = getMultiAdapter((self.root, request), name='+hierarchy')
47 self.assertEquals(
48 ['http://bugs.launchpad.dev/crumb-tester',
49 'http://bugs.launchpad.dev/crumb-tester/+bug/%d' % self.bug.id],
50 [crumb.url for crumb in hierarchy.items()])
51 self.assertEquals(
52 ["Crumb Tester", "Bug #%d" % self.bug.id],
53 [crumb.text for crumb in hierarchy.items()])
54
55 def test_bugtask_child_on_vhost(self):
56 request = make_fake_request(
57 'http://bugs.launchpad.dev/%s/+bug/%d/+activity' % (
58 self.product.name, self.bug.id),
59 [self.root, self.product, self.bug.default_bugtask])
60 hierarchy = getMultiAdapter((self.root, request), name='+hierarchy')
61 self.assertEquals(
62 ['http://bugs.launchpad.dev/crumb-tester',
63 'http://bugs.launchpad.dev/crumb-tester/+bug/%d' % self.bug.id],
64 [crumb.url for crumb in hierarchy.items()])
65 self.assertEquals(
66 ["Crumb Tester", "Bug #%d" % self.bug.id],
67 [crumb.text for crumb in hierarchy.items()])
68
69
70def test_suite():
71 return unittest.TestLoader().loadTestsFromName(__name__)
Revision history for this message
Gavin Panella (allenap) wrote :

Also see the screenshot of what it looks like now:

  http://launchpadlibrarian.net/30272857/post-review.png

Revision history for this message
Michael Nelson (michael.nelson) wrote :

> Also see the screenshot of what it looks like now:
>
> http://launchpadlibrarian.net/30272857/post-review.png

Thanks Gavin, for the screenshot and for adding the breadcrumb - looks great!

So, as we discussed, r=me assuming that:

1. The lack of padding between the heading and the table will be fixed by either the placement of the new breadcrumbs or a general css rule to apply padding to tables within portlets (as you've correctly got it in a top-portlet now), and,

2. The table itself will be redesigned as part of the bugs ui work later, and will include a link to the relevant product's bugtask for an activity log entry when it is different from the product displayed in the traversal (and above the app. tabs).

-M.

review: Approve (ui)
Revision history for this message
Celso Providelo (cprov) wrote :
Download full text (8.1 KiB)

> === modified file 'lib/lp/bugs/browser/bugtask.py'
> --- lib/lp/bugs/browser/bugtask.py 2009-08-10 21:05:59 +0000
> +++ lib/lp/bugs/browser/bugtask.py 2009-08-13 16:47:38 +0000
> @@ -14,6 +14,7 @@
> 'BugTargetView',
> 'BugTaskContextMenu',
> 'BugTaskCreateQuestionView',
> + 'BugTaskBreadcrumbBuilder',
> 'BugTaskEditView',
> 'BugTaskExpirableListingView',
> 'BugTaskListingItem',
> @@ -45,7 +46,6 @@
> import re
> from simplejson import dumps
> import urllib
> -from urlparse import urlparse, urlunparse
> from operator import attrgetter, itemgetter
>
> from zope import component
> @@ -116,6 +116,7 @@
> from lp.registry.interfaces.sourcepackage import ISourcePackage
> from canonical.launchpad.interfaces.validation import (
> valid_upstreamtask, validate_distrotask)
> +from canonical.launchpad.webapp.breadcrumb import BreadcrumbBuilder
> from canonical.launchpad.webapp.interfaces import (
> ILaunchBag, NotFoundError, UnexpectedFormData)
>
> @@ -3490,3 +3491,10 @@
> return_dict[key] = cgi.escape(return_dict[key])
>
> return "%(old_value)s &#8594; %(new_value)s" % return_dict
> +
> +
> +class BugTaskBreadcrumbBuilder(BreadcrumbBuilder):
> + """Builds a breadcrumb for an `IBugTask`."""
> + @property
> + def text(self):
> + return self.context.bug.displayname
>

Nice! It will look much nicer when we have the breadcrumbs below the
heading section.

> === modified file 'lib/lp/bugs/configure.zcml'
> --- lib/lp/bugs/configure.zcml 2009-07-23 13:44:13 +0000
> +++ lib/lp/bugs/configure.zcml 2009-08-13 16:47:38 +0000
> @@ -263,6 +263,12 @@
> <adapter
> factory="lp.bugs.browser.bugtask.assignee_renderer"
> name="assignee"/>
> + <adapter
> + provides="canonical.launchpad.webapp.interfaces.IBreadcrumbBuilder"
> + for="lp.bugs.interfaces.bugtask.IBugTask"
> + factory="lp.bugs.browser.bugtask.BugTaskBreadcrumbBuilder"
> + permission="zope.Public"/>
> +
>
> <!-- NullBugTask -->
>
>

It looks like you have TABs before and after this comment.

> === modified file 'lib/lp/bugs/stories/bugs/xx-bug-activity.txt'
> --- lib/lp/bugs/stories/bugs/xx-bug-activity.txt 2009-08-06 13:51:38 +0000
> +++ lib/lp/bugs/stories/bugs/xx-bug-activity.txt 2009-08-13 16:47:38 +0000
> @@ -7,16 +7,19 @@
> ... 'mozilla-firefox/+bug/3/+activity')
> >>> main_content = find_main_content(anon_browser.contents)
>
> -The page heading contains a link back to the bug page.
> +The page contains a link back to the bug page:
>
> - >>> bug_link = main_content.p.a
> - >>> print '%s --> %s' % (extract_text(bug_link), bug_link['href'])
> - Bug #3: Bug Title Test --> /debian/+source/mozilla-firefox/+bug/3
> + >>> document = find_tag_by_id(anon_browser.contents, 'document')
> + >>> bug_link = document.find(
> + ... 'a', href=lambda href: href.endswith('/+bug/3'))
> + >>> print '%s\n--> %s' % (extract_text(bug_link), bug_link['href'])
> + Bug #3
> + --> http://bugs.launchpad.dev/debian/+source/mozilla-firefox/+bug/3
>

I wonder if there would be any value in using print_locatio...

Read more...

review: Approve
Revision history for this message
Gavin Panella (allenap) wrote :
Download full text (4.4 KiB)

On Thu, 13 Aug 2009 17:09:06 -0000
Celso Providelo <email address hidden> wrote:

> Review: Approve

Woohoo! Thank you :)

...
> > === modified file 'lib/lp/bugs/configure.zcml'
> > --- lib/lp/bugs/configure.zcml 2009-07-23 13:44:13 +0000
> > +++ lib/lp/bugs/configure.zcml 2009-08-13 16:47:38 +0000
> > @@ -263,6 +263,12 @@
> > <adapter
> > factory="lp.bugs.browser.bugtask.assignee_renderer"
> > name="assignee"/>
> > + <adapter
> > + provides="canonical.launchpad.webapp.interfaces.IBreadcrumbBuilder"
> > + for="lp.bugs.interfaces.bugtask.IBugTask"
> > + factory="lp.bugs.browser.bugtask.BugTaskBreadcrumbBuilder"
> > + permission="zope.Public"/>
> > +
> >
> > <!-- NullBugTask -->
> >
> >
>
> It looks like you have TABs before and after this comment.

All of the configure.zcml files generated during the move from c/l to
lp/* are chock full of weird whitespace. I started a utility to clean
this up a while back, but have not finished it. If I fix this comment,
I need to fix all the whitespace in this file, so I'd like to leave it
for now, until I have an automated solution.

>
> > === modified file 'lib/lp/bugs/stories/bugs/xx-bug-activity.txt'
> > --- lib/lp/bugs/stories/bugs/xx-bug-activity.txt 2009-08-06 13:51:38 +0000
> > +++ lib/lp/bugs/stories/bugs/xx-bug-activity.txt 2009-08-13 16:47:38 +0000
> > @@ -7,16 +7,19 @@
> > ... 'mozilla-firefox/+bug/3/+activity')
> > >>> main_content = find_main_content(anon_browser.contents)
> >
> > -The page heading contains a link back to the bug page.
> > +The page contains a link back to the bug page:
> >
> > - >>> bug_link = main_content.p.a
> > - >>> print '%s --> %s' % (extract_text(bug_link), bug_link['href'])
> > - Bug #3: Bug Title Test --> /debian/+source/mozilla-firefox/+bug/3
> > + >>> document = find_tag_by_id(anon_browser.contents, 'document')
> > + >>> bug_link = document.find(
> > + ... 'a', href=lambda href: href.endswith('/+bug/3'))
> > + >>> print '%s\n--> %s' % (extract_text(bug_link), bug_link['href'])
> > + Bug #3
> > + --> http://bugs.launchpad.dev/debian/+source/mozilla-firefox/+bug/3
> >
>
> I wonder if there would be any value in using print_location() helper
> here. it prints the hierarchy, not exactly the links, but we know the
> links are properly rendered by BreadcrumbBuilder (we have specific
> tests for that).
>
> What do you think ?

I've never used print_location() before, but you're right, it fits the
bill nicely. I've had to modify it to work with the new application
tabs, so maybe you could have a look at the attached diff just to make
sure it's okay?

>
> > The title repeats the bug number for clarity.
> >
> > >>> print extract_text(main_content.h1)
> > - Activity log for bug #3
> > + Activity log for bug #3 - Bug Title Test
> >
> > The activity log itself is presented as a table.
> >
> > @@ -27,9 +30,9 @@
> > >>> for row in main_content.table('tr'):
> > ... print_row(row)
> > Date | Who | What changed | Old value | New value | Message
> > - 10 Aug 05 16:30 | Sample Person | bug | | | assigne...

Read more...

=== modified file 'lib/canonical/launchpad/testing/pages.py'
--- lib/canonical/launchpad/testing/pages.py 2009-06-25 05:30:52 +0000
+++ lib/canonical/launchpad/testing/pages.py 2009-08-14 09:19:59 +0000
@@ -542,15 +542,26 @@
542def print_location_apps(contents):542def print_location_apps(contents):
543 """Print the application tabs' text and URL."""543 """Print the application tabs' text and URL."""
544 location_apps = find_tag_by_id(contents, 'lp-apps')544 location_apps = find_tag_by_id(contents, 'lp-apps')
545 for tab in location_apps.findAll('span'):545 if location_apps is None:
546 tab_text = extract_text(tab)546 location_apps = first_tag_by_class(contents, 'location-portlet')
547 if tab['class'].find('active') != -1:547 if location_apps is not None:
548 tab_text += ' (selected)'548 location_apps = location_apps.ul.findAll('li')
549 if tab.a:549 else:
550 link = tab.a['href']550 location_apps = location_apps.findAll('span')
551 else:551 if location_apps is None:
552 link = 'not linked'552 print "(Application tabs omitted)"
553 print "* %s - %s" % (tab_text, link)553 elif len(location_apps) == 0:
554 print "(No application tabs)"
555 else:
556 for tab in location_apps:
557 tab_text = extract_text(tab)
558 if tab['class'].find('active') != -1:
559 tab_text += ' (selected)'
560 if tab.a:
561 link = tab.a['href']
562 else:
563 link = 'not linked'
564 print "* %s - %s" % (tab_text, link)
554565
555566
556def print_tag_with_id(contents, id):567def print_tag_with_id(contents, id):
557568
=== modified file 'lib/lp/bugs/stories/bugs/xx-bug-activity.txt'
--- lib/lp/bugs/stories/bugs/xx-bug-activity.txt 2009-08-13 12:59:41 +0000
+++ lib/lp/bugs/stories/bugs/xx-bug-activity.txt 2009-08-14 09:20:08 +0000
@@ -7,19 +7,20 @@
7 ... 'mozilla-firefox/+bug/3/+activity')7 ... 'mozilla-firefox/+bug/3/+activity')
8 >>> main_content = find_main_content(anon_browser.contents)8 >>> main_content = find_main_content(anon_browser.contents)
99
10The page contains a link back to the bug page:10
1111The page contains a link back to the bug page in the breadcrumbs and
12 >>> document = find_tag_by_id(anon_browser.contents, 'document')12the main heading repeats the bug number for clarity:
13 >>> bug_link = document.find(13
14 ... 'a', href=lambda href: href.endswith('/+bug/3'))14 >>> print_location(anon_browser.contents)
15 >>> print '%s\n--> %s' % (extract_text(bug_link), bug_link['href'])15 Hierarchy: Launchpad > Debian > ?mozilla-firefox? package > Bug #3
16 Bug #316 Tabs:
17 --> http://bugs.launchpad.dev/debian/+source/mozilla-firefox/+bug/317 * Overview - http://launchpad.dev/debian/+source/mozilla-firefox
1818 * Code - http://code.launchpad.dev/debian/+source/mozilla-firefox
19The title repeats the bug number for clarity.19 * Bugs (selected) - http://bugs.launchpad.dev/debian/+source/mozilla-firefox
2020 * Blueprints - not linked
21 >>> print extract_text(main_content.h1)21 * Translations - not linked
22 Activity log for bug #3 - Bug Title Test22 * Answers - http://answers.launchpad.dev/debian/+source/mozilla-firefox
23 Main heading: Activity log for bug #3: Bug Title Test
2324
24The activity log itself is presented as a table.25The activity log itself is presented as a table.
2526
2627
=== modified file 'lib/lp/bugs/templates/bug-activity.pt'
--- lib/lp/bugs/templates/bug-activity.pt 2009-08-13 14:06:31 +0000
+++ lib/lp/bugs/templates/bug-activity.pt 2009-08-13 14:25:35 +0000
@@ -7,7 +7,7 @@
77
8 <div metal:fill-slot="heading">8 <div metal:fill-slot="heading">
9 <h1>9 <h1>
10 Activity log for bug #<span tal:replace="context/bug/id" /> -10 Activity log for bug #<span tal:replace="context/bug/id" />:
11 <span tal:replace="context/bug/title" />11 <span tal:replace="context/bug/title" />
12 </h1>12 </h1>
13 </div>13 </div>
Revision history for this message
Gavin Panella (allenap) wrote :

Several tests broke, and one of them required quite a lot of work to
fix. Basically, breadcrumbs were still being generated when viewing a
bug that the user did not have permission to view. I've added a test to
test_breadcrumbs and changed the adapter to cope with this scenario.

I've attached an incremental diff.

Thanks in advance.

=== modified file 'lib/lp/bugs/browser/bugtask.py'
--- lib/lp/bugs/browser/bugtask.py 2009-08-13 14:07:18 +0000
+++ lib/lp/bugs/browser/bugtask.py 2009-08-14 16:30:27 +0000
@@ -62,6 +62,7 @@
62from zope.schema.interfaces import IContextSourceBinder, IList62from zope.schema.interfaces import IContextSourceBinder, IList
63from zope.schema.vocabulary import (63from zope.schema.vocabulary import (
64 getVocabularyRegistry, SimpleVocabulary, SimpleTerm)64 getVocabularyRegistry, SimpleVocabulary, SimpleTerm)
65from zope.security.interfaces import Unauthorized
65from zope.security.proxy import (66from zope.security.proxy import (
66 isinstance as zope_isinstance, removeSecurityProxy)67 isinstance as zope_isinstance, removeSecurityProxy)
67from zope.traversing.interfaces import IPathAdapter68from zope.traversing.interfaces import IPathAdapter
@@ -3495,6 +3496,18 @@
34953496
3496class BugTaskBreadcrumbBuilder(BreadcrumbBuilder):3497class BugTaskBreadcrumbBuilder(BreadcrumbBuilder):
3497 """Builds a breadcrumb for an `IBugTask`."""3498 """Builds a breadcrumb for an `IBugTask`."""
3499
3498 @property3500 @property
3499 def text(self):3501 def text(self):
3500 return self.context.bug.displayname3502 return self.context.bug.displayname
3503
3504 def make_breadcrumb(self):
3505 """Return a breadcrumb for this `BugTask`.
3506
3507 If the user does not have permission to view the bug for
3508 whatever reason, don't return a breadcrumb.
3509 """
3510 try:
3511 return super(BugTaskBreadcrumbBuilder, self).make_breadcrumb()
3512 except Unauthorized:
3513 return None
35013514
=== modified file 'lib/lp/bugs/stories/bug-release-management/nomination-navigation.txt'
--- lib/lp/bugs/stories/bug-release-management/nomination-navigation.txt 2009-07-01 13:16:44 +0000
+++ lib/lp/bugs/stories/bug-release-management/nomination-navigation.txt 2009-08-14 14:44:07 +0000
@@ -11,7 +11,7 @@
11 ... 'http://bugs.launchpad.dev/ubuntu/+source/mozilla-firefox/+bug/1'11 ... 'http://bugs.launchpad.dev/ubuntu/+source/mozilla-firefox/+bug/1'
12 ... '/nominations/2/+editstatus')12 ... '/nominations/2/+editstatus')
13 >>> print_location(admin_browser.contents)13 >>> print_location(admin_browser.contents)
14 Hierarchy: Launchpad > Ubuntu > ?mozilla-firefox? package14 Hierarchy: Launchpad > Ubuntu > ?mozilla-firefox? package > Bug #1
15 Tabs:15 Tabs:
16 * Overview - http://launchpad.dev/ubuntu/+source/mozilla-firefox16 * Overview - http://launchpad.dev/ubuntu/+source/mozilla-firefox
17 * Code - http://code.launchpad.dev/ubuntu/+source/mozilla-firefox17 * Code - http://code.launchpad.dev/ubuntu/+source/mozilla-firefox
1818
=== modified file 'lib/lp/bugs/stories/bugs/xx-bug-index.txt'
--- lib/lp/bugs/stories/bugs/xx-bug-index.txt 2009-07-31 08:12:47 +0000
+++ lib/lp/bugs/stories/bugs/xx-bug-index.txt 2009-08-14 15:11:58 +0000
@@ -10,9 +10,25 @@
10 >>> anon_browser.title10 >>> anon_browser.title
11 '...Blackhole Trash folder...'11 '...Blackhole Trash folder...'
1212
13The bug id in the upper left corner of the page is linked to the bug itself.13The breadcrumbs and other navigation include a link to the bug itself.
1414
15 >>> anon_browser.getLink('Bug #2').click()15 >>> print_location(anon_browser.contents)
16 Hierarchy: Launchpad > Debian > ?mozilla-firefox? package > Bug #2 (blackhole)
17 Tabs:
18 * Overview - http://launchpad.dev/debian/+source/mozilla-firefox
19 * Code - http://code.launchpad.dev/debian/+source/mozilla-firefox
20 * Bugs (selected) - http://bugs.launchpad.dev/debian/+source/mozilla-firefox
21 * Blueprints - not linked
22 * Translations - not linked
23 * Answers - http://answers.launchpad.dev/debian/+source/mozilla-firefox
24 Main heading: Blackhole Trash folder
25
26The bug id in the upper left corner of the main page content is also
27linked to the bug itself.
28
29 >>> bug_link = first_tag_by_class(
30 ... anon_browser.contents, 'object identifier').a
31 >>> anon_browser.open(bug_link.get('href'))
16 >>> print anon_browser.title32 >>> print anon_browser.title
17 Bug #2 in Tomcat:...Blackhole Trash folder...33 Bug #2 in Tomcat:...Blackhole Trash folder...
1834
1935
=== modified file 'lib/lp/bugs/tests/test_breadcrumbs.py'
--- lib/lp/bugs/tests/test_breadcrumbs.py 2009-08-13 13:57:47 +0000
+++ lib/lp/bugs/tests/test_breadcrumbs.py 2009-08-14 16:32:02 +0000
@@ -10,7 +10,8 @@
10from canonical.lazr.testing.menus import make_fake_request10from canonical.lazr.testing.menus import make_fake_request
11from canonical.launchpad.webapp.publisher import RootObject11from canonical.launchpad.webapp.publisher import RootObject
12from canonical.testing import DatabaseFunctionalLayer12from canonical.testing import DatabaseFunctionalLayer
13from lp.testing import TestCaseWithFactory13from lp.testing import (
14 ANONYMOUS, TestCaseWithFactory, login)
1415
1516
16class TestBugTaskBreadcrumbBuilder(TestCaseWithFactory):17class TestBugTaskBreadcrumbBuilder(TestCaseWithFactory):
@@ -18,7 +19,7 @@
18 layer = DatabaseFunctionalLayer19 layer = DatabaseFunctionalLayer
1920
20 def setUp(self):21 def setUp(self):
21 TestCaseWithFactory.setUp(self)22 super(TestBugTaskBreadcrumbBuilder, self).setUp()
22 self.product = self.factory.makeProduct(23 self.product = self.factory.makeProduct(
23 name='crumb-tester', displayname="Crumb Tester")24 name='crumb-tester', displayname="Crumb Tester")
24 self.bug = self.factory.makeBug(product=self.product)25 self.bug = self.factory.makeBug(product=self.product)
@@ -66,6 +67,23 @@
66 ["Crumb Tester", "Bug #%d" % self.bug.id],67 ["Crumb Tester", "Bug #%d" % self.bug.id],
67 [crumb.text for crumb in hierarchy.items()])68 [crumb.text for crumb in hierarchy.items()])
6869
70 def test_bugtask_private_bug(self):
71 # A breadcrumb is not generated for a bug that the user does
72 # not have permission to view.
73 login('foo.bar@canonical.com')
74 self.bug.setPrivate(True, self.bug.owner)
75 login(ANONYMOUS)
76 request = make_fake_request(
77 'http://bugs.launchpad.dev/%s/+bug/%d/+activity' % (
78 self.product.name, self.bug.id),
79 [self.root, self.product, self.bug.default_bugtask])
80 hierarchy = getMultiAdapter((self.root, request), name='+hierarchy')
81 self.assertEquals(
82 ['http://bugs.launchpad.dev/crumb-tester'],
83 [crumb.url for crumb in hierarchy.items()])
84 self.assertEquals(
85 ["Crumb Tester"], [crumb.text for crumb in hierarchy.items()])
86
6987
70def test_suite():88def test_suite():
71 return unittest.TestLoader().loadTestsFromName(__name__)89 return unittest.TestLoader().loadTestsFromName(__name__)
Revision history for this message
Celso Providelo (cprov) wrote :

> Several tests broke, and one of them required quite a lot of work to
> fix. Basically, breadcrumbs were still being generated when viewing a
> bug that the user did not have permission to view. I've added a test to
> test_breadcrumbs and changed the adapter to cope with this scenario.
>
> I've attached an incremental diff.
>
> Thanks in advance.

Gavin.

I'm happy with the way you fixed breadcrumbs for private bugs, thanks for catching this problem before landing.

Regarding the previous diff, thanks for fixing print_location() and you are right that having 'UTC' repeated on each row would be bad ... the bug report is enough to sort this problem in the future.

All good!

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/bugs/templates/bug-activity.pt'
--- lib/lp/bugs/templates/bug-activity.pt 2009-07-17 17:59:07 +0000
+++ lib/lp/bugs/templates/bug-activity.pt 2009-08-12 13:02:26 +0000
@@ -1,20 +1,19 @@
1<html1<bug-activity
2 xmlns="http://www.w3.org/1999/xhtml"2 xmlns="http://www.w3.org/1999/xhtml"
3 xmlns:tal="http://xml.zope.org/namespaces/tal"3 xmlns:tal="http://xml.zope.org/namespaces/tal"
4 xmlns:metal="http://xml.zope.org/namespaces/metal"4 xmlns:metal="http://xml.zope.org/namespaces/metal"
5 xmlns:i18n="http://xml.zope.org/namespaces/i18n"5 xmlns:i18n="http://xml.zope.org/namespaces/i18n"
6 xml:lang="en"6 metal:use-macro="view/macro:page/main_only">
7 lang="en"
8 dir="ltr"
9 metal:use-macro="view/macro:page/onecolumn"
10>
11 <body>
12<div metal:fill-slot="main">
137
14 <div id="maincontent">8 <div metal:fill-slot="heading">
15 <p tal:content="structure view/current_bugtask/fmt:link" />
16 <h1>Activity log for bug #<span tal:replace="context/bug/id" /></h1>9 <h1>Activity log for bug #<span tal:replace="context/bug/id" /></h1>
10 </div>
1711
12 <div metal:fill-slot="main">
13 <div class="top-portlet">
14 <p tal:content="structure context/fmt:link" />
15 </div>
16 <div class="yui-g">
18 <table class="listing">17 <table class="listing">
19 <thead>18 <thead>
20 <tr>19 <tr>
@@ -39,9 +38,6 @@
39 </tr>38 </tr>
40 </tbody>39 </tbody>
41 </table>40 </table>
41 </div>
42 </div>42 </div>
4343</bug-activity>
44</div>
45
46</body>
47</html>