Merge lp:~salgado/launchpad/breadcrumbs-for-leafs into lp:launchpad
- breadcrumbs-for-leafs
- Merge into devel
Proposed by
Guilherme Salgado
Status: | Merged |
---|---|
Approved by: | Brad Crittenden |
Approved revision: | no longer in the source branch. |
Merged at revision: | not available |
Proposed branch: | lp:~salgado/launchpad/breadcrumbs-for-leafs |
Merge into: | lp:launchpad |
Diff against target: | None lines |
To merge this branch: | bzr merge lp:~salgado/launchpad/breadcrumbs-for-leafs |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Brad Crittenden (community) | code | Approve | |
Review via email:
|
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Guilherme Salgado (salgado) wrote : | # |
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Brad Crittenden (bac) wrote : | # |
This change looks great Salgado.
review:
Approve
(code)
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Brad Crittenden (bac) wrote : | # |
This change looks great Salgado.
review:
Approve
(code)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'lib/canonical/launchpad/browser/launchpad.py' |
2 | --- lib/canonical/launchpad/browser/launchpad.py 2009-08-26 07:59:49 +0000 |
3 | +++ lib/canonical/launchpad/browser/launchpad.py 2009-09-01 18:06:25 +0000 |
4 | @@ -34,6 +34,7 @@ |
5 | import urllib |
6 | from datetime import timedelta, datetime |
7 | |
8 | +from zope.app import zapi |
9 | from zope.datetime import parseDatetimetz, tzinfo, DateTimeError |
10 | from zope.component import getUtility, queryAdapter |
11 | from zope.interface import implements |
12 | @@ -96,6 +97,7 @@ |
13 | LaunchpadFormView, LaunchpadView, Link, Navigation, |
14 | StandardLaunchpadFacets, canonical_name, canonical_url, custom_widget, |
15 | stepto) |
16 | +from canonical.launchpad.webapp.breadcrumb import Breadcrumb |
17 | from canonical.launchpad.webapp.interfaces import ( |
18 | IBreadcrumb, ILaunchBag, ILaunchpadRoot, INavigationMenu, |
19 | NotFoundError, POSTToNonCanonicalURL) |
20 | @@ -234,25 +236,48 @@ |
21 | breadcrumbs.append(breadcrumb) |
22 | |
23 | host = URI(self.request.getURL()).host |
24 | - if (len(breadcrumbs) == 0 |
25 | - or host == allvhosts.configs['mainsite'].hostname): |
26 | - return breadcrumbs |
27 | - |
28 | - # If we got this far it means we have breadcrumbs and we're not on the |
29 | - # mainsite, so we'll sneak an extra breadcrumb for the vhost we're on. |
30 | - vhost = host.split('.')[0] |
31 | - |
32 | - # Iterate over the context of our breadcrumbs in reverse order and for |
33 | - # the first one we find an adapter named after the vhost we're on, |
34 | - # generate an extra breadcrumb and insert it in our list. |
35 | - for idx, breadcrumb in reversed(list(enumerate(breadcrumbs))): |
36 | - extra_breadcrumb = queryAdapter( |
37 | - breadcrumb.context, IBreadcrumb, name=vhost) |
38 | - if extra_breadcrumb is not None: |
39 | - breadcrumbs.insert(idx + 1, extra_breadcrumb) |
40 | - break |
41 | + mainhost = allvhosts.configs['mainsite'].hostname |
42 | + if len(breadcrumbs) != 0 and host != mainhost: |
43 | + # We have breadcrumbs and we're not on the mainsite, so we'll |
44 | + # sneak an extra breadcrumb for the vhost we're on. |
45 | + vhost = host.split('.')[0] |
46 | + |
47 | + # Iterate over the context of our breadcrumbs in reverse order and |
48 | + # for the first one we find an adapter named after the vhost we're |
49 | + # on, generate an extra breadcrumb and insert it in our list. |
50 | + for idx, breadcrumb in reversed(list(enumerate(breadcrumbs))): |
51 | + extra_breadcrumb = queryAdapter( |
52 | + breadcrumb.context, IBreadcrumb, name=vhost) |
53 | + if extra_breadcrumb is not None: |
54 | + breadcrumbs.insert(idx + 1, extra_breadcrumb) |
55 | + break |
56 | + if len(breadcrumbs): |
57 | + page_crumb = self.makeBreadcrumbForRequestedPage() |
58 | + if page_crumb: |
59 | + breadcrumbs.append(page_crumb) |
60 | return breadcrumbs |
61 | |
62 | + def makeBreadcrumbForRequestedPage(self): |
63 | + """Return an `IBreadcrumb` for the requested page. |
64 | + |
65 | + The `IBreadcrumb` for the requested page is created using the current |
66 | + URL and the page's name (i.e. the last path segment of the URL). |
67 | + |
68 | + If the requested page (as specified in self.request) is the default |
69 | + one for the last traversed object, return None. |
70 | + """ |
71 | + url = self.request.getURL() |
72 | + last_segment = URI(url).path.split('/')[-1] |
73 | + default_view_name = zapi.getDefaultViewName( |
74 | + self.request.traversed_objects[-1], self.request) |
75 | + if last_segment.startswith('+') and last_segment != default_view_name: |
76 | + breadcrumb = Breadcrumb(None) |
77 | + breadcrumb._url = url |
78 | + breadcrumb.text = last_segment |
79 | + return breadcrumb |
80 | + else: |
81 | + return None |
82 | + |
83 | @property |
84 | def display_breadcrumbs(self): |
85 | """Return whether the breadcrumbs should be displayed.""" |
86 | @@ -260,6 +285,7 @@ |
87 | # to display it as it will simply repeat the context.title. |
88 | return len(self.items) > 1 |
89 | |
90 | + |
91 | class MaintenanceMessage: |
92 | """Display a maintenance message if the control file is present and |
93 | it contains a valid iso format time. |
94 | |
95 | === modified file 'lib/canonical/launchpad/webapp/breadcrumb.py' |
96 | --- lib/canonical/launchpad/webapp/breadcrumb.py 2009-08-25 12:35:23 +0000 |
97 | +++ lib/canonical/launchpad/webapp/breadcrumb.py 2009-08-31 17:40:56 +0000 |
98 | @@ -27,6 +27,7 @@ |
99 | implements(IBreadcrumb) |
100 | |
101 | text = None |
102 | + _url = None |
103 | |
104 | def __init__(self, context): |
105 | self.context = context |
106 | @@ -46,7 +47,10 @@ |
107 | |
108 | @property |
109 | def url(self): |
110 | - return canonical_url(self.context, rootsite=self.rootsite) |
111 | + if self._url is None: |
112 | + return canonical_url(self.context, rootsite=self.rootsite) |
113 | + else: |
114 | + return self._url |
115 | |
116 | @property |
117 | def icon(self): |
118 | |
119 | === modified file 'lib/canonical/launchpad/webapp/tests/test_breadcrumbs.py' |
120 | --- lib/canonical/launchpad/webapp/tests/test_breadcrumbs.py 2009-08-25 12:35:23 +0000 |
121 | +++ lib/canonical/launchpad/webapp/tests/test_breadcrumbs.py 2009-08-31 17:40:56 +0000 |
122 | @@ -37,6 +37,29 @@ |
123 | self.assertEquals(Breadcrumb(cookbook).rootsite, 'cooking') |
124 | |
125 | |
126 | +class TestExtraBreadcrumbForLeafPageOnHierarchyView(BaseBreadcrumbTestCase): |
127 | + """When the current page is not the object's default one (+index), we add |
128 | + an extra breadcrumb for it. |
129 | + """ |
130 | + |
131 | + def setUp(self): |
132 | + super(TestExtraBreadcrumbForLeafPageOnHierarchyView, self).setUp() |
133 | + login('test@canonical.com') |
134 | + self.product = self.factory.makeProduct(name='crumb-tester') |
135 | + self.product_url = canonical_url(self.product) |
136 | + |
137 | + def test_default_page(self): |
138 | + urls = self._getBreadcrumbsURLs( |
139 | + self.product_url, [self.root, self.product]) |
140 | + self.assertEquals(urls, [self.product_url]) |
141 | + |
142 | + def test_non_default_page(self): |
143 | + downloads_url = "%s/+download" % self.product_url |
144 | + urls = self._getBreadcrumbsURLs( |
145 | + downloads_url, [self.root, self.product]) |
146 | + self.assertEquals(urls, [self.product_url, downloads_url]) |
147 | + |
148 | + |
149 | class TestExtraVHostBreadcrumbsOnHierarchyView(BaseBreadcrumbTestCase): |
150 | """How our breadcrumbs behave when using a vhost other than the main one? |
151 | |
152 | |
153 | === modified file 'lib/lp/bugs/browser/tests/test_breadcrumbs.py' |
154 | --- lib/lp/bugs/browser/tests/test_breadcrumbs.py 2009-08-24 20:28:33 +0000 |
155 | +++ lib/lp/bugs/browser/tests/test_breadcrumbs.py 2009-08-31 17:40:56 +0000 |
156 | @@ -35,9 +35,11 @@ |
157 | url = canonical_url( |
158 | self.bug.default_bugtask, rootsite='bugs', view_name='+activity') |
159 | urls = self._getBreadcrumbsURLs(url, self.traversed_objects) |
160 | - self.assertEquals(urls[-1], self.bugtask_url) |
161 | + self.assertEquals(urls[-1], "%s/+activity" % self.bugtask_url) |
162 | + self.assertEquals(urls[-2], self.bugtask_url) |
163 | texts = self._getBreadcrumbsTexts(url, self.traversed_objects) |
164 | - self.assertEquals(texts[-1], "Bug #%d" % self.bug.id) |
165 | + self.assertEquals(texts[-1], "+activity") |
166 | + self.assertEquals(texts[-2], "Bug #%d" % self.bug.id) |
167 | |
168 | def test_bugtask_private_bug(self): |
169 | # A breadcrumb is not generated for a bug that the user does |
170 | @@ -45,8 +47,7 @@ |
171 | login('foo.bar@canonical.com') |
172 | self.bug.setPrivate(True, self.bug.owner) |
173 | login(ANONYMOUS) |
174 | - url = canonical_url( |
175 | - self.bug.default_bugtask, rootsite='bugs', view_name='+activity') |
176 | + url = canonical_url(self.bug.default_bugtask, rootsite='bugs') |
177 | self.assertEquals( |
178 | ['http://launchpad.dev/crumb-tester', |
179 | 'http://bugs.launchpad.dev/crumb-tester'], |
180 | |
181 | === modified file 'lib/lp/bugs/stories/bug-release-management/nomination-navigation.txt' |
182 | --- lib/lp/bugs/stories/bug-release-management/nomination-navigation.txt 2009-08-27 08:32:39 +0000 |
183 | +++ lib/lp/bugs/stories/bug-release-management/nomination-navigation.txt 2009-09-01 17:31:05 +0000 |
184 | @@ -12,7 +12,7 @@ |
185 | ... '/nominations/2/+editstatus') |
186 | >>> print_location(admin_browser.contents) |
187 | Hierarchy: Ubuntu > ?mozilla-firefox? package > |
188 | - Bugs on mozilla-firefox > Bug #1 |
189 | + Bugs on mozilla-firefox > Bug #1... |
190 | Tabs: |
191 | * Overview - http://launchpad.dev/ubuntu/+source/mozilla-firefox |
192 | * Code - http://code.launchpad.dev/ubuntu/+source/mozilla-firefox |
193 | |
194 | === modified file 'lib/lp/bugs/stories/bugs/xx-bug-activity.txt' |
195 | --- lib/lp/bugs/stories/bugs/xx-bug-activity.txt 2009-08-28 14:31:15 +0000 |
196 | +++ lib/lp/bugs/stories/bugs/xx-bug-activity.txt 2009-09-01 17:31:05 +0000 |
197 | @@ -7,13 +7,12 @@ |
198 | ... 'mozilla-firefox/+bug/3/+activity') |
199 | >>> main_content = find_main_content(anon_browser.contents) |
200 | |
201 | - |
202 | The page contains a link back to the bug page in the breadcrumbs and |
203 | the main heading repeats the bug number for clarity: |
204 | |
205 | >>> print_location(anon_browser.contents) |
206 | Hierarchy: Debian > ?mozilla-firefox? package > |
207 | - Bugs on mozilla-firefox > Bug #3 |
208 | + Bugs on mozilla-firefox > Bug #3... |
209 | Tabs: |
210 | * Overview - http://launchpad.dev/debian/+source/mozilla-firefox |
211 | * Code - http://code.launchpad.dev/debian/+source/mozilla-firefox |
212 | |
213 | === modified file 'lib/lp/bugs/stories/bugs/xx-link-bug-to-branch.txt' |
214 | --- lib/lp/bugs/stories/bugs/xx-link-bug-to-branch.txt 2009-08-28 11:12:06 +0000 |
215 | +++ lib/lp/bugs/stories/bugs/xx-link-bug-to-branch.txt 2009-09-01 17:31:05 +0000 |
216 | @@ -57,6 +57,7 @@ |
217 | >>> link.click() |
218 | >>> print extract_text(find_tag_by_id( |
219 | ... user_browser.contents, 'maincontent')) |
220 | + Mozilla Firefox... |
221 | Remove bug branch link |
222 | Are you sure you want to remove the link between Bug #1: Firefox does |
223 | not support SVG and the branch lp://dev/~name12/firefox/main? |
224 | |
225 | === modified file 'lib/lp/code/stories/branches/xx-branch-deletion.txt' |
226 | --- lib/lp/code/stories/branches/xx-branch-deletion.txt 2009-08-12 00:58:24 +0000 |
227 | +++ lib/lp/code/stories/branches/xx-branch-deletion.txt 2009-09-01 17:31:05 +0000 |
228 | @@ -25,6 +25,7 @@ |
229 | >>> delete_link.click() |
230 | >>> print extract_text(find_main_content(browser.contents)) |
231 | Delete branch |
232 | + Mozilla Firefox... |
233 | Branch deletion is permanent. |
234 | or Cancel |
235 | |
236 | @@ -68,7 +69,7 @@ |
237 | >>> admin_browser.open(branch_location) |
238 | >>> admin_browser.getLink('Delete branch').click() |
239 | >>> print extract_text(find_main_content(admin_browser.contents)) |
240 | - Delete branch |
241 | + Delete branch... |
242 | This branch cannot be deleted as it has 1 branch sharing revisions. |
243 | |
244 | However, you can delete a branch that's the official branch of a source |
245 | |
246 | === modified file 'lib/lp/registry/stories/foaf/xx-admin-person-review.txt' |
247 | --- lib/lp/registry/stories/foaf/xx-admin-person-review.txt 2009-08-01 00:02:55 +0000 |
248 | +++ lib/lp/registry/stories/foaf/xx-admin-person-review.txt 2009-09-01 17:31:05 +0000 |
249 | @@ -47,7 +47,7 @@ |
250 | |
251 | The page also contains a link back to the +review page. |
252 | |
253 | - >>> link = admin_browser.getLink(url='+review') |
254 | + >>> link = admin_browser.getLink(url='+review', index=1) |
255 | >>> print link.text |
256 | edit[IMG] Review the user's Launchpad information |
257 | |
258 | |
259 | === modified file 'lib/lp/registry/stories/product/xx-product-files.txt' |
260 | --- lib/lp/registry/stories/product/xx-product-files.txt 2009-08-27 17:50:21 +0000 |
261 | +++ lib/lp/registry/stories/product/xx-product-files.txt 2009-09-01 17:31:05 +0000 |
262 | @@ -98,6 +98,7 @@ |
263 | >>> main_content = find_main_content(tbird_owner.contents) |
264 | >>> print extract_text(main_content) |
265 | Download project files |
266 | + Mozilla Thunderbird... |
267 | No download files exist for this project... |
268 | Add download file for release: 0.8 |
269 | >>> tbird_owner.getControl('Delete Files') |
270 | |
271 | === modified file 'lib/lp/soyuz/stories/soyuz/xx-distribution-archives.txt' |
272 | --- lib/lp/soyuz/stories/soyuz/xx-distribution-archives.txt 2009-08-12 13:00:09 +0000 |
273 | +++ lib/lp/soyuz/stories/soyuz/xx-distribution-archives.txt 2009-09-01 17:31:05 +0000 |
274 | @@ -52,6 +52,7 @@ |
275 | >>> main_content = find_main_content(anon_browser.contents) |
276 | >>> print extract_text(main_content) |
277 | Copy Archives related to Ubuntu Linux |
278 | + Ubuntu... |
279 | 'Copy' archives containing packages copied from other archives |
280 | (the main archive or PPAs) for a distribution. |
281 | ... |
282 |
= Summary =
According to <https:/ /wiki.canonical .com/Launchpad/ UI/Navigation>, we'll
want breadcrumbs for the current page when it's not the default one for
the context, so this branch adds that.
== Proposed fix ==
Add a new method to the Hierarchy view, which builds an extra breadcrumb
for the requested page. This breadcrumb is then appended to the list of
breadcrumbs returned by Hierarchy.items
== Implementation details ==
We should be using the page's title as the breadcrumb's text, but that's
not easy to get programmatically as we need the template name to look up
the page title in pagetitles.py. Once our views have a page_title
attribute and we get rid of pagetitles.py, it'll be easy to change the
breadcrumb to use the page's title instead of its name.
== Tests ==
./bin/tests -vvt test_breadcrumbs
== Demo and Q/A ==
= Launchpad lint =
Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.
Linting changed files: code/stories/ branches/ xx-branch- deletion. txt /launchpad/ webapp/ tests/test_ breadcrumbs. py bugs/stories/ bugs/xx- link-bug- to-branch. txt bugs/stories/ bug-release- management/ nomination- navigation. txt /launchpad/ browser/ launchpad. py /launchpad/ webapp/ breadcrumb. py bugs/stories/ bugs/xx- bug-activity. txt registry/ stories/ foaf/xx- admin-person- review. txt registry/ stories/ product/ xx-product- files.txt soyuz/stories/ soyuz/xx- distribution- archives. txt bugs/browser/ tests/test_ breadcrumbs. py
lib/lp/
lib/canonical
lib/lp/
lib/lp/
lib/canonical
lib/canonical
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
== Pylint notices ==
lib/canonical/ launchpad/ browser/ launchpad. py
106: [F0401] Unable to import 'lazr.uri' (No module named uri)