Merge lp:~elachuni/ubuntu-webcatalog/navigation into lp:ubuntu-webcatalog

Proposed by Anthony Lenton
Status: Merged
Approved by: Danny Tamez
Approved revision: 42
Merged at revision: 32
Proposed branch: lp:~elachuni/ubuntu-webcatalog/navigation
Merge into: lp:ubuntu-webcatalog
Diff against target: 432 lines (+176/-24)
9 files modified
src/webcatalog/admin.py (+2/-0)
src/webcatalog/models/applications.py (+5/-0)
src/webcatalog/static/css/webcatalog.css (+53/-2)
src/webcatalog/templates/webcatalog/application_detail.html (+16/-2)
src/webcatalog/templates/webcatalog/application_overview_snippet.html (+9/-5)
src/webcatalog/templates/webcatalog/department_overview.html (+18/-0)
src/webcatalog/tests/test_views.py (+45/-10)
src/webcatalog/urls.py (+3/-1)
src/webcatalog/views.py (+25/-4)
To merge this branch: bzr merge lp:~elachuni/ubuntu-webcatalog/navigation
Reviewer Review Type Date Requested Status
Danny Tamez (community) Approve
Review via email: mp+66636@code.launchpad.net

Commit message

Add a right sidebar navigation portlet to switch between distroseries

Description of the change

Overview
========
Add a right sidebar navigation portlet to switch between distroseries

Details
=======

The portlet was added both on the application details and the department overview screens. For that we needed to provide a distroseries-specific department overview url.
For consistency, I made the distroseries-specific url for apps specify the distroseries before the package name.

While I was there, I
- Fixed the breadcrumbs background to work with apps with extra-long names (like "A tool for the blackbox/fluxbox window managers that runs commands" -- package bbrun)

- Registered DistroSeries with the admin

To post a comment you must log in.
41. By Anthony Lenton

Test fix.

42. By Anthony Lenton

Just bumping rev.

Revision history for this message
Danny Tamez (zematynnad) wrote :

Looks fine.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/webcatalog/admin.py'
--- src/webcatalog/admin.py 2011-06-17 16:21:59 +0000
+++ src/webcatalog/admin.py 2011-07-01 17:17:27 +0000
@@ -25,6 +25,7 @@
25from webcatalog.models import (25from webcatalog.models import (
26 Application,26 Application,
27 Department,27 Department,
28 DistroSeries,
28 )29 )
2930
30__metaclass__ = type31__metaclass__ = type
@@ -41,3 +42,4 @@
4142
42admin.site.register(Application, ApplicationAdmin)43admin.site.register(Application, ApplicationAdmin)
43admin.site.register(Department)44admin.site.register(Department)
45admin.site.register(DistroSeries)
4446
=== modified file 'src/webcatalog/models/applications.py'
--- src/webcatalog/models/applications.py 2011-06-29 14:42:24 +0000
+++ src/webcatalog/models/applications.py 2011-07-01 17:17:27 +0000
@@ -99,6 +99,11 @@
99 stripped = [x.strip() for x in self.categories.split(';')]99 stripped = [x.strip() for x in self.categories.split(';')]
100 return set(x for x in stripped if x)100 return set(x for x in stripped if x)
101101
102 def available_distroseries(self):
103 """Return the set of distroseries for which this app is available"""
104 return DistroSeries.objects.filter(
105 application__package_name=self.package_name).order_by('version')
106
102 @classmethod107 @classmethod
103 def from_json(cls, data):108 def from_json(cls, data):
104 app = Application()109 app = Application()
105110
=== modified file 'src/webcatalog/static/css/webcatalog.css'
--- src/webcatalog/static/css/webcatalog.css 2011-06-23 14:49:53 +0000
+++ src/webcatalog/static/css/webcatalog.css 2011-07-01 17:17:27 +0000
@@ -16,6 +16,8 @@
16 -webkit-box-shadow: #bbb 2px 2px 5px 1px;16 -webkit-box-shadow: #bbb 2px 2px 5px 1px;
17 margin: 12px 0 20px;17 margin: 12px 0 20px;
18 font-size: 14px;18 font-size: 14px;
19 width: 684px;
20 float: left;
19}21}
2022
21#sc-mockup h2 {23#sc-mockup h2 {
@@ -44,7 +46,7 @@
44}46}
45.screenshot {47.screenshot {
46 float: right;48 float: right;
47 margin-right: 16px;49 margin: 0 16px;
48}50}
4951
50.noscreenshot {52.noscreenshot {
@@ -73,14 +75,63 @@
7375
74/* End software centre mockup */76/* End software centre mockup */
7577
78/* Right sidebar */
79#rightbar {
80 float: right;
81 width: 206px;
82 margin-top: 28px;
83}
84
85.portletheader {
86 padding: 10px 8px;
87 font-size: 14px;
88 background: #DD4814;
89 color: white;
90 -moz-border-radius: 4px 4px 0 0;
91 -webkit-border-radius: 4px 4px 0 0;
92 -khtml-border-radius: 4px 4px 0 0;
93 border-radius: 4px 4px 0 0;
94}
95
96ul.portletactions {
97 font-size: 12px;
98 list-style-image: none;
99}
100
101ul.portletactions li {
102 border-bottom: 1px dotted gray;
103 margin: 0;
104}
105
106ul.portletactions li a, ul.portletactions li span {
107 padding: 8px;
108 display: block;
109 color: black;
110}
111
112ul.portletactions li.active span, ul.portletactions a:hover {
113 background: transparent url("/assets/images/subnav_active_bg.png");
114 color: #E24912;
115 text-decoration: none;
116}
117/* End right sidebar */
118
119.main-column {
120 width: 684px;
121 float: left;
122}
76.app-overview-row {123.app-overview-row {
77 height: 36px;124 min-height: 36px;
78 padding: 2px;125 padding: 2px;
79}126}
80.app-overview-row img {127.app-overview-row img {
81 float: left;128 float: left;
82 margin-right: 10px;129 margin-right: 10px;
83}130}
131.app-overview-text {
132 float: left;
133 width: 634px;
134}
84.app-overview-row h3 {135.app-overview-row h3 {
85 padding: 0;136 padding: 0;
86 margin: 0;137 margin: 0;
87138
=== added file 'src/webcatalog/static/images/applications-other-64.png'
88Binary files src/webcatalog/static/images/applications-other-64.png 1970-01-01 00:00:00 +0000 and src/webcatalog/static/images/applications-other-64.png 2011-07-01 17:17:27 +0000 differ139Binary files src/webcatalog/static/images/applications-other-64.png 1970-01-01 00:00:00 +0000 and src/webcatalog/static/images/applications-other-64.png 2011-07-01 17:17:27 +0000 differ
=== added file 'src/webcatalog/static/images/applications-other.png'
89Binary files src/webcatalog/static/images/applications-other.png 1970-01-01 00:00:00 +0000 and src/webcatalog/static/images/applications-other.png 2011-07-01 17:17:27 +0000 differ140Binary files src/webcatalog/static/images/applications-other.png 1970-01-01 00:00:00 +0000 and src/webcatalog/static/images/applications-other.png 2011-07-01 17:17:27 +0000 differ
=== modified file 'src/webcatalog/static/images/breadcrumbs_bg.png'
90Binary files src/webcatalog/static/images/breadcrumbs_bg.png 2011-06-23 14:20:52 +0000 and src/webcatalog/static/images/breadcrumbs_bg.png 2011-07-01 17:17:27 +0000 differ141Binary files src/webcatalog/static/images/breadcrumbs_bg.png 2011-06-23 14:20:52 +0000 and src/webcatalog/static/images/breadcrumbs_bg.png 2011-07-01 17:17:27 +0000 differ
=== added file 'src/webcatalog/static/images/subnav_active_bg.png'
91Binary files src/webcatalog/static/images/subnav_active_bg.png 1970-01-01 00:00:00 +0000 and src/webcatalog/static/images/subnav_active_bg.png 2011-07-01 17:17:27 +0000 differ142Binary files src/webcatalog/static/images/subnav_active_bg.png 1970-01-01 00:00:00 +0000 and src/webcatalog/static/images/subnav_active_bg.png 2011-07-01 17:17:27 +0000 differ
=== modified file 'src/webcatalog/templates/webcatalog/application_detail.html'
--- src/webcatalog/templates/webcatalog/application_detail.html 2011-06-29 09:24:48 +0000
+++ src/webcatalog/templates/webcatalog/application_detail.html 2011-07-01 17:17:27 +0000
@@ -7,13 +7,27 @@
77
8{% block content %}8{% block content %}
9 {% include "webcatalog/breadcrumbs_snippet.html" %}9 {% include "webcatalog/breadcrumbs_snippet.html" %}
1010 <div id="rightbar">
11 <div class="portlet">
12 <div class="portletheader">Available versions</div>
13 <ul class="portletactions">
14 {% for ds in available_distroseries %}
15 <li class="item{% ifequal ds.code_name distroseries %} active{% endifequal %}{% if forloop.last %} last{% endif %}">
16 {% ifequal ds.code_name distroseries %}
17 <span>Ubuntu {{ ds.version }} ({{ ds.code_name }})</span>
18 {% else %}
19 <a href="{% url wc-package-detail ds.code_name application.package_name %}">Ubuntu {{ ds.version }} ({{ ds.code_name }})</a>
20 {% endifequal %}</li>
21 {% endfor %}
22 </ul>
23 </div>
24 </div>
11 <div id="sc-mockup">25 <div id="sc-mockup">
12 <div class="header">26 <div class="header">
13 {% if application.icon %}27 {% if application.icon %}
14 <img class="icon64" src="{{ application.icon.url }}"/>28 <img class="icon64" src="{{ application.icon.url }}"/>
15 {% else %}29 {% else %}
16 <img class="icon64" src="{{ STATIC_URL }}images/noicon_32.png"/>30 <img class="icon64" src="{{ STATIC_URL }}images/applications-other-64.png"/>
17 {% endif %}31 {% endif %}
1832
19 <h2>{{ application.name }}</h2>33 <h2>{{ application.name }}</h2>
2034
=== modified file 'src/webcatalog/templates/webcatalog/application_overview_snippet.html'
--- src/webcatalog/templates/webcatalog/application_overview_snippet.html 2011-06-28 15:03:12 +0000
+++ src/webcatalog/templates/webcatalog/application_overview_snippet.html 2011-07-01 17:17:27 +0000
@@ -1,11 +1,15 @@
1<div class="app-overview-row">1<div class="app-overview-row">
2 <div>
2 {% if app.icon %}3 {% if app.icon %}
3 <img src="{{ app.icon.url }}" width="32" height="32" />4 <img src="{{ app.icon.url }}" width="32" height="32" />
4 {% else %}5 {% else %}
5 <img src="{{ STATIC_URL }}images/noicon_32.png"/>6 <img src="{{ STATIC_URL }}images/applications-other.png"/>
6 {% endif %}7 {% endif %}
7 <h3>8 </div>
8 <a href="{% url wc-package-detail app.distroseries.code_name app.package_name %}">{{ app.name }}</a>9 <div class="app-overview-text">
9 </h3>10 <h3>
10 <p>{{ app.comment }}</p>11 <a href="{% url wc-package-detail app.distroseries.code_name app.package_name %}">{{ app.name }}</a>
12 </h3>
13 <p>{{ app.comment }}</p>
14 </div>
11</div>15</div>
1216
=== modified file 'src/webcatalog/templates/webcatalog/department_overview.html'
--- src/webcatalog/templates/webcatalog/department_overview.html 2011-06-28 15:03:12 +0000
+++ src/webcatalog/templates/webcatalog/department_overview.html 2011-07-01 17:17:27 +0000
@@ -7,6 +7,23 @@
7{% block content %}7{% block content %}
8 {% include "webcatalog/breadcrumbs_snippet.html" %}8 {% include "webcatalog/breadcrumbs_snippet.html" %}
99
10 <div id="rightbar">
11 <div class="portlet">
12 <div class="portletheader">Available versions</div>
13 <ul class="portletactions">
14 {% for ds in available_distroseries %}
15 <li class="item{% ifequal ds.code_name distroseries %} active{% endifequal %}{% if forloop.last %} last{% endif %}">
16 {% ifequal ds.code_name distroseries %}
17 <span>Ubuntu {{ ds.version }} ({{ ds.code_name }})</span>
18 {% else %}
19 <a href="{% url wc-department ds.code_name dept.id %}">Ubuntu {{ ds.version }} ({{ ds.code_name }})</a>
20 {% endifequal %}</li>
21 {% endfor %}
22 </ul>
23 </div>
24 </div>
25
26<div class="main-column">
10{% if subdepts %}27{% if subdepts %}
11<h3>{% trans "Subsections" %}:</h3>28<h3>{% trans "Subsections" %}:</h3>
1229
@@ -26,5 +43,6 @@
26{% else %}43{% else %}
27<p>{% trans "No applications found." %}</p>44<p>{% trans "No applications found." %}</p>
28{% endif %}45{% endif %}
46</div>
2947
30{% endblock %}48{% endblock %}
3149
=== modified file 'src/webcatalog/tests/test_views.py'
--- src/webcatalog/tests/test_views.py 2011-06-29 15:24:23 +0000
+++ src/webcatalog/tests/test_views.py 2011-07-01 17:17:27 +0000
@@ -68,7 +68,8 @@
68 if not detail_package:68 if not detail_package:
69 detail_package = app.package_name69 detail_package = app.package_name
7070
71 url = reverse('wc-package-detail', args=[detail_package, detail_distro])71 url = reverse('wc-package-detail', args=[detail_distro,
72 detail_package])
7273
73 if useragent:74 if useragent:
74 response = self.client.get(url, HTTP_USER_AGENT=useragent)75 response = self.client.get(url, HTTP_USER_AGENT=useragent)
@@ -134,6 +135,22 @@
134 '<a href="{lucid_app_url}">your version of Ubuntu</a>.'.format(135 '<a href="{lucid_app_url}">your version of Ubuntu</a>.'.format(
135 lucid_app_url=lucid_app_url))136 lucid_app_url=lucid_app_url))
136137
138 def test_includes_right_navigation(self):
139 lucid = self.factory.make_distroseries(code_name='lucid',
140 version='10.04')
141 maverick = self.factory.make_distroseries(code_name='maverick',
142 version='10.10')
143 lucid_app = self.factory.make_application(package_name='pkgfoo',
144 distroseries=lucid)
145 maverick_app = self.factory.make_application(package_name='pkgfoo',
146 distroseries=maverick)
147
148 response, app = self.get_app_and_response(name="Foobar")
149
150 for ds in ['lucid', 'maverick']:
151 url = reverse('wc-package-detail', args=[ds, 'pkgfoo'])
152 self.assertContains(response, '<a href="{0}">Ubuntu'.format(url))
153
137154
138class ApplicationDetailNoSeriesTestCase(TestCaseWithFactory):155class ApplicationDetailNoSeriesTestCase(TestCaseWithFactory):
139156
@@ -155,7 +172,7 @@
155172
156 self.assertRedirects(173 self.assertRedirects(
157 response, reverse(174 response, reverse(
158 'wc-package-detail', args=['pkgfoo', default_distro]))175 'wc-package-detail', args=[default_distro, 'pkgfoo']))
159176
160 def test_redirects_to_ua_distroseries(self):177 def test_redirects_to_ua_distroseries(self):
161 # If a distroseries is not included in the url, but we178 # If a distroseries is not included in the url, but we
@@ -175,7 +192,7 @@
175192
176 self.assertRedirects(193 self.assertRedirects(
177 response, reverse(194 response, reverse(
178 'wc-package-detail', args=['pkgfoo', 'lucid']))195 'wc-package-detail', args=['lucid', 'pkgfoo']))
179196
180197
181class SearchTestCase(TestCaseWithFactory):198class SearchTestCase(TestCaseWithFactory):
@@ -297,7 +314,8 @@
297 dept = self.factory.make_department('foo')314 dept = self.factory.make_department('foo')
298 subdept = self.factory.make_department('bar', parent=dept)315 subdept = self.factory.make_department('bar', parent=dept)
299316
300 response = self.client.get(reverse('wc-department', args=[dept.id]))317 response = self.client.get(reverse('wc-department', args=[
318 settings.DEFAULT_DISTRO, dept.id]))
301319
302 self.assertContains(response, reverse('wc-department',320 self.assertContains(response, reverse('wc-department',
303 args=[subdept.id]))321 args=[subdept.id]))
@@ -307,7 +325,8 @@
307 dept = self.factory.make_department('bar')325 dept = self.factory.make_department('bar')
308 app.departments.add(dept)326 app.departments.add(dept)
309327
310 response = self.client.get(reverse('wc-department', args=[dept.id]))328 response = self.client.get(reverse('wc-department', args=[
329 app.distroseries.code_name, dept.id]))
311330
312 self.assertContains(response, reverse('wc-package-detail',331 self.assertContains(response, reverse('wc-package-detail',
313 args=[app.distroseries.code_name, app.package_name]))332 args=[app.distroseries.code_name, app.package_name]))
@@ -315,17 +334,19 @@
315 def test_department_with_no_subdepts_doesnt_contain_header(self):334 def test_department_with_no_subdepts_doesnt_contain_header(self):
316 dept = self.factory.make_department('bar')335 dept = self.factory.make_department('bar')
317336
318 response = self.client.get(reverse('wc-department', args=[dept.id]))337 response = self.client.get(reverse('wc-department', args=[
338 settings.DEFAULT_DISTRO, dept.id]))
319339
320 self.assertNotContains(response, 'Subsections')340 self.assertNotContains(response, 'Subsections')
321341
322 def test_department_shows_paginated_results(self):342 def test_department_shows_paginated_results(self):
323 dept = self.factory.make_department('bar')343 dept = self.factory.make_department('bar')
344 lucid = self.factory.make_distroseries(code_name='lucid')
324 for count in range(3):345 for count in range(3):
325 app = self.factory.make_application()346 app = self.factory.make_application(distroseries=lucid)
326 app.departments.add(dept)347 app.departments.add(dept)
327348
328 url = reverse('wc-department', args=[dept.id])349 url = reverse('wc-department', args=['lucid', dept.id])
329 with patch_settings(PAGE_BATCH_SIZE=2):350 with patch_settings(PAGE_BATCH_SIZE=2):
330 response = self.client.get(url)351 response = self.client.get(url)
331352
@@ -340,8 +361,7 @@
340361
341 def test_invalid_page_doesnt_error(self):362 def test_invalid_page_doesnt_error(self):
342 dept = self.factory.make_department('bar')363 dept = self.factory.make_department('bar')
343 url = reverse('wc-department', args=[dept.id])364 url = reverse('wc-department', args=[settings.DEFAULT_DISTRO, dept.id])
344
345 response = self.client.get(url, data={'page': 'aef8'})365 response = self.client.get(url, data={'page': 'aef8'})
346 page = response.context['page']366 page = response.context['page']
347 self.assertEqual(1, page.number)367 self.assertEqual(1, page.number)
@@ -353,3 +373,18 @@
353 response = self.client.get(url, data={'page': '999'})373 response = self.client.get(url, data={'page': '999'})
354 page = response.context['page']374 page = response.context['page']
355 self.assertEqual(1, page.number)375 self.assertEqual(1, page.number)
376
377 def test_department_includes_right_navigation(self):
378 dept = self.factory.make_department('bar')
379 lucid = self.factory.make_distroseries(code_name='lucid',
380 version='10.04')
381 maverick = self.factory.make_distroseries(code_name='maverick',
382 version='10.10')
383
384 response = self.client.get(reverse('wc-department', args=[
385 settings.DEFAULT_DISTRO, dept.id]))
386
387 for ds in ['lucid', 'maverick']:
388 url = reverse('wc-department', args=[ds, dept.id])
389 self.assertContains(response, '<a href="{0}">Ubuntu'.format(url))
390
356391
=== modified file 'src/webcatalog/urls.py'
--- src/webcatalog/urls.py 2011-06-29 12:47:09 +0000
+++ src/webcatalog/urls.py 2011-07-01 17:17:27 +0000
@@ -31,9 +31,11 @@
3131
32urlpatterns = patterns('webcatalog.views',32urlpatterns = patterns('webcatalog.views',
33 url(r'^$', 'index', name='wc-index'),33 url(r'^$', 'index', name='wc-index'),
34 url(r'^department/(?P<distro>[-.+\w]+)/(?P<dept_id>\d+)/$',
35 'department_overview', name='wc-department'),
34 url(r'^department/(?P<dept_id>\d+)/$', 'department_overview',36 url(r'^department/(?P<dept_id>\d+)/$', 'department_overview',
35 name='wc-department'),37 name='wc-department'),
36 url(r'^applications/(?P<package_name>[-.+\w]+)/(?P<distro>[-.+\w]+)/$',38 url(r'^applications/(?P<distro>[-.+\w]+)/(?P<package_name>[-.+\w]+)/$',
37 'application_detail', name="wc-package-detail"),39 'application_detail', name="wc-package-detail"),
38 url(r'^applications/(?P<package_name>[-.+\w]+)/$', 'application_detail',40 url(r'^applications/(?P<package_name>[-.+\w]+)/$', 'application_detail',
39 name="wc-package-detail"),41 name="wc-package-detail"),
4042
=== modified file 'src/webcatalog/views.py'
--- src/webcatalog/views.py 2011-06-30 16:38:56 +0000
+++ src/webcatalog/views.py 2011-07-01 17:17:27 +0000
@@ -39,6 +39,7 @@
39from webcatalog.models import (39from webcatalog.models import (
40 Application,40 Application,
41 Department,41 Department,
42 DistroSeries,
42 )43 )
43from webcatalog.utilities import UserAgentString44from webcatalog.utilities import UserAgentString
4445
@@ -95,11 +96,24 @@
95 context_instance=context)96 context_instance=context)
9697
9798
98def department_overview(request, dept_id):99def department_overview(request, dept_id, distro=None):
100 if distro is None:
101 useragent = UserAgentString(request.META.get('HTTP_USER_AGENT', ''))
102 # Check for the distroseries in the useragent, if we have it,
103 # redirect there.
104 if useragent.distroseries:
105 distro = useragent.distroseries
106 else:
107 distro = settings.DEFAULT_DISTRO
108 return HttpResponseRedirect(
109 reverse('wc-department', args=[distro, dept_id]))
110
99 dept = get_object_or_404(Department, pk=dept_id)111 dept = get_object_or_404(Department, pk=dept_id)
100 subdepts = Department.objects.filter(parent=dept)112 subdepts = Department.objects.filter(parent=dept)
101 subdepts = subdepts.order_by('name')113 subdepts = subdepts.order_by('name')
102 apps = Application.objects.filter(departments=dept)114
115 apps = Application.objects.filter(departments=dept,
116 distroseries__code_name=distro)
103 apps = apps.order_by('name')117 apps = apps.order_by('name')
104 paginator = Paginator(apps, settings.PAGE_BATCH_SIZE)118 paginator = Paginator(apps, settings.PAGE_BATCH_SIZE)
105 page_num = _get_page_num_from_request(request, paginator)119 page_num = _get_page_num_from_request(request, paginator)
@@ -108,6 +122,8 @@
108 'subdepts': subdepts,122 'subdepts': subdepts,
109 'page': paginator.page(page_num),123 'page': paginator.page(page_num),
110 'breadcrumbs': dept.crumbs(),124 'breadcrumbs': dept.crumbs(),
125 'available_distroseries': DistroSeries.objects.all(),
126 'distroseries': distro,
111 })127 })
112 return render_to_response('webcatalog/department_overview.html',128 return render_to_response('webcatalog/department_overview.html',
113 context_instance=context)129 context_instance=context)
@@ -125,11 +141,16 @@
125 distro = settings.DEFAULT_DISTRO141 distro = settings.DEFAULT_DISTRO
126 return HttpResponseRedirect(142 return HttpResponseRedirect(
127 reverse('wc-package-detail',143 reverse('wc-package-detail',
128 args=[package_name, distro]))144 args=[distro, package_name]))
129145
130 app = get_object_or_404(Application, package_name=package_name,146 app = get_object_or_404(Application, package_name=package_name,
131 distroseries__code_name=distro)147 distroseries__code_name=distro)
148 atts = {'application': app,
149 'available_distroseries': app.available_distroseries(),
150 'breadcrumbs': app.crumbs(),
151 'distroseries': distro,
152 }
132153
133 return render_to_response(154 return render_to_response(
134 'webcatalog/application_detail.html', RequestContext(155 'webcatalog/application_detail.html', RequestContext(
135 request, dict(application=app, breadcrumbs=app.crumbs())))156 request, atts))

Subscribers

People subscribed via source and target branches