Merge lp://staging/~henninge/launchpad/bug-434055-combined into lp://staging/launchpad

Proposed by Henning Eggers
Status: Merged
Approved by: Brad Crittenden
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp://staging/~henninge/launchpad/bug-434055-combined
Merge into: lp://staging/launchpad
Diff against target: None lines
To merge this branch: bzr merge lp://staging/~henninge/launchpad/bug-434055-combined
Reviewer Review Type Date Requested Status
Brad Crittenden (community) release-critical Approve
Graham Binns (community) code Approve
Review via email: mp+12229@code.staging.launchpad.net
To post a comment you must log in.
Revision history for this message
Henning Eggers (henninge) wrote :

= Summary =

Bug 434055 and bug 434195.
Convert 'hasspefications-specs.pt' to 3.0 design. Convert specificationstarget-assignments to UI 3.0.

This is a combined branch, jtv's part for bug 434195 has already been reviewed.

== Implementation details ==

The trouble with hasspecificaitons-spece.pt was that it is used in many different contexts and that each hat its own ApplicationMenu. The menus shared most links in varying combinations, so I aggregated the links into one Mixin that is now used in all Menus.

I converted the ApplicationMenus to NavigationMenus to use them as global-actions. This was the most straight-forward way of conversion without loosing any functionality. I also changed that for specificationstarget-assignments where jtv had removed the menu completely.

I fixed the Breadcrumb for the specifications vhost as it was repeating the context name (like "Foo Bar >> Specifications involving Foo Bar", now it's "Foo Bar >> Blueprints") and I normalized on using the term "blueprint" ;-)

Some label and page_title work was also done.

Did I forget to mention anything?

== Code ==

I will paste a separate diff to show the differences to jtv's branch.

Revision history for this message
Henning Eggers (henninge) wrote :
Download full text (29.6 KiB)

=== modified file 'lib/canonical/launchpad/pagetitles.py'
--- lib/canonical/launchpad/pagetitles.py 2009-09-22 00:49:37 +0000
+++ lib/canonical/launchpad/pagetitles.py 2009-09-22 15:03:45 +0000
@@ -402,13 +402,6 @@

 hasannouncements_index = ContextDisplayName('%s news and announcements')

-def hasspecifications_specs(context, view):
- """Return the secifications title for the context."""
- if IPerson.providedBy(context):
- return "Blueprints involving %s" % context.title
- else:
- return "Blueprints for %s" % context.title
-
 hassprints_sprints = ContextTitle("Events related to %s")

 # launchpad_debug doesn't need a title.

=== modified file 'lib/lp/blueprints/browser/specificationgoal.py'
--- lib/lp/blueprints/browser/specificationgoal.py 2009-09-18 19:47:24 +0000
+++ lib/lp/blueprints/browser/specificationgoal.py 2009-09-22 14:54:36 +0000
@@ -30,6 +30,7 @@
     """

     label = "Set feature goals"
+ page_title = "Feature goals"

     @cachedproperty
     def spec_filter(self):

=== modified file 'lib/lp/blueprints/browser/specificationtarget.py'
--- lib/lp/blueprints/browser/specificationtarget.py 2009-09-22 09:23:42 +0000
+++ lib/lp/blueprints/browser/specificationtarget.py 2009-09-22 14:54:36 +0000
@@ -6,6 +6,7 @@
 __metaclass__ = type

 __all__ = [
+ 'HasSpecificationsMenuMixin',
     'HasSpecificationsView',
     'RegisterABlueprintButtonView',
     'SpecificationAssignmentsView',
@@ -30,7 +31,7 @@

 from canonical.config import config
 from canonical.launchpad import _
-from canonical.launchpad.webapp import LaunchpadView
+from canonical.launchpad.webapp import LaunchpadView, Link
 from canonical.launchpad.webapp.batching import BatchNavigator
 from canonical.launchpad.webapp.breadcrumb import Breadcrumb
 from canonical.launchpad.helpers import shortlist
@@ -39,6 +40,48 @@
 from canonical.lazr.utils import smartquote

+class HasSpecificationsMenuMixin(object):
+
+ def listall(self):
+ """Return a link to show all blueprints."""
+ text = 'List all blueprints'
+ return Link('+specs?show=all', text, icon='blueprint')
+
+ def listaccepted(self):
+ """Return a link to show the approved goals."""
+ text = 'List approved blueprints'
+ return Link('+specs?acceptance=accepted', text, icon='blueprint')
+
+ def listproposed(self):
+ """Return a link to show the proposed goals."""
+ text = 'List proposed blueprints'
+ return Link('+specs?acceptance=proposed', text, icon='blueprint')
+
+ def listdeclined(self):
+ """Return a link to show the declined goals."""
+ text = 'List declined blueprints'
+ return Link('+specs?acceptance=declined', text, icon='blueprint')
+
+ def doc(self):
+ text = 'List documentation'
+ return Link('+documentation', text, icon='info')
+
+ def setgoals(self):
+ """Return a link to set the series goals."""
+ text = 'Set series goals'
+ return Link('+setgoals', text, icon='edit')
+
+ def assignments(self):
+ """Return a link to show the people assigned to the blueprint."""
+ text = 'Assignments'
+ return Link('+assignments', t...

Revision history for this message
Graham Binns (gmb) wrote :

I'm happy for this to land once the no-arg methods of HasSpecificationsMenuMixin are made into properties, as discussed on IRC.

review: Approve (code)
Revision history for this message
Brad Crittenden (bac) :
review: Approve (release-critical)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/canonical/launchpad/pagetitles.py'
--- lib/canonical/launchpad/pagetitles.py 2009-09-20 19:40:47 +0000
+++ lib/canonical/launchpad/pagetitles.py 2009-09-22 15:10:46 +0000
@@ -402,13 +402,6 @@
402402
403hasannouncements_index = ContextDisplayName('%s news and announcements')403hasannouncements_index = ContextDisplayName('%s news and announcements')
404404
405def hasspecifications_specs(context, view):
406 """Return the secifications title for the context."""
407 if IPerson.providedBy(context):
408 return "Blueprints involving %s" % context.title
409 else:
410 return "Blueprints for %s" % context.title
411
412hassprints_sprints = ContextTitle("Events related to %s")405hassprints_sprints = ContextTitle("Events related to %s")
413406
414# launchpad_debug doesn't need a title.407# launchpad_debug doesn't need a title.
@@ -848,8 +841,6 @@
848 """Return the page title for a specificationtarget."""841 """Return the page title for a specificationtarget."""
849 return view.title842 return view.title
850843
851specificationtarget_assignments = ContextTitle('Blueprint assignments for %s')
852
853specificationtarget_workload = ContextTitle('Blueprint workload in %s')844specificationtarget_workload = ContextTitle('Blueprint workload in %s')
854845
855sprint_attend = ContextTitle('Register your attendance at %s')846sprint_attend = ContextTitle('Register your attendance at %s')
856847
=== modified file 'lib/lp/blueprints/browser/configure.zcml'
--- lib/lp/blueprints/browser/configure.zcml 2009-09-21 12:39:15 +0000
+++ lib/lp/blueprints/browser/configure.zcml 2009-09-22 10:20:47 +0000
@@ -56,13 +56,17 @@
56 name="+specs"56 name="+specs"
57 template="../templates/hasspecifications-specs.pt"/>57 template="../templates/hasspecifications-specs.pt"/>
58 <browser:page58 <browser:page
59 name="+assignments"
60 template="../templates/specificationtarget-assignments.pt"/>
61 <browser:page
62 name="+portlet-latestspecs"59 name="+portlet-latestspecs"
63 template="../templates/specificationtarget-portlet-latestspecs.pt"/>60 template="../templates/specificationtarget-portlet-latestspecs.pt"/>
64 </browser:pages>61 </browser:pages>
65 <browser:page62 <browser:page
63 name="+assignments"
64 for="lp.blueprints.interfaces.sprint.ISprint"
65 class="canonical.launchpad.browser.SpecificationAssignmentsView"
66 facet="specifications"
67 permission="zope.Public"
68 template="../templates/specificationtarget-assignments.pt"/>
69 <browser:page
66 name="+edit"70 name="+edit"
67 for="lp.blueprints.interfaces.sprint.ISprint"71 for="lp.blueprints.interfaces.sprint.ISprint"
68 class="lp.blueprints.browser.sprint.SprintEditView"72 class="lp.blueprints.browser.sprint.SprintEditView"
@@ -537,13 +541,16 @@
537 name="+specs"541 name="+specs"
538 template="../templates/hasspecifications-specs.pt"/>542 template="../templates/hasspecifications-specs.pt"/>
539 <browser:page543 <browser:page
540 name="+assignments"
541 template="../templates/specificationtarget-assignments.pt"/>
542 <browser:page
543 name="+portlet-latestspecs"544 name="+portlet-latestspecs"
544 template="../templates/specificationtarget-portlet-latestspecs.pt"/>545 template="../templates/specificationtarget-portlet-latestspecs.pt"/>
545 </browser:pages>546 </browser:pages>
546 <browser:page547 <browser:page
548 name="+assignments"
549 for="lp.blueprints.interfaces.specificationtarget.IHasSpecifications"
550 class="lp.blueprints.browser.specificationtarget.SpecificationAssignmentsView"
551 permission="zope.Public"
552 template="../templates/specificationtarget-assignments.pt"/>
553 <browser:page
547 name="+register-a-blueprint-button"554 name="+register-a-blueprint-button"
548 for="lp.blueprints.interfaces.specificationtarget.ISpecificationTarget"555 for="lp.blueprints.interfaces.specificationtarget.ISpecificationTarget"
549 class="lp.blueprints.browser.specificationtarget.RegisterABlueprintButtonView"556 class="lp.blueprints.browser.specificationtarget.RegisterABlueprintButtonView"
@@ -585,12 +592,16 @@
585 name="+specs"592 name="+specs"
586 template="../templates/hasspecifications-specs.pt"/>593 template="../templates/hasspecifications-specs.pt"/>
587 <browser:page594 <browser:page
588 name="+assignments"
589 template="../templates/specificationtarget-assignments.pt"/>
590 <browser:page
591 name="+portlet-latestspecs"595 name="+portlet-latestspecs"
592 template="../templates/specificationtarget-portlet-latestspecs.pt"/>596 template="../templates/specificationtarget-portlet-latestspecs.pt"/>
593 </browser:pages>597 </browser:pages>
598 <browser:page
599 name="+assignments"
600 for="lp.registry.interfaces.project.IProject"
601 class="lp.blueprints.browser.specificationtarget.SpecificationAssignmentsView"
602 facet="specifications"
603 permission="zope.Public"
604 template="../templates/specificationtarget-assignments.pt"/>
594605
595 <browser:page606 <browser:page
596 name="+addspec"607 name="+addspec"
597608
=== modified file 'lib/lp/blueprints/browser/specificationgoal.py'
--- lib/lp/blueprints/browser/specificationgoal.py 2009-09-18 19:47:24 +0000
+++ lib/lp/blueprints/browser/specificationgoal.py 2009-09-22 15:02:41 +0000
@@ -30,6 +30,7 @@
30 """30 """
3131
32 label = "Set feature goals"32 label = "Set feature goals"
33 page_title = "Feature goals"
3334
34 @cachedproperty35 @cachedproperty
35 def spec_filter(self):36 def spec_filter(self):
3637
=== modified file 'lib/lp/blueprints/browser/specificationtarget.py'
--- lib/lp/blueprints/browser/specificationtarget.py 2009-09-17 21:20:14 +0000
+++ lib/lp/blueprints/browser/specificationtarget.py 2009-09-22 15:02:41 +0000
@@ -6,8 +6,10 @@
6__metaclass__ = type6__metaclass__ = type
77
8__all__ = [8__all__ = [
9 'HasSpecificationsMenuMixin',
9 'HasSpecificationsView',10 'HasSpecificationsView',
10 'RegisterABlueprintButtonView',11 'RegisterABlueprintButtonView',
12 'SpecificationAssignmentsView',
11 'SpecificationDocumentationView',13 'SpecificationDocumentationView',
12 ]14 ]
1315
@@ -29,7 +31,7 @@
2931
30from canonical.config import config32from canonical.config import config
31from canonical.launchpad import _33from canonical.launchpad import _
32from canonical.launchpad.webapp import LaunchpadView34from canonical.launchpad.webapp import LaunchpadView, Link
33from canonical.launchpad.webapp.batching import BatchNavigator35from canonical.launchpad.webapp.batching import BatchNavigator
34from canonical.launchpad.webapp.breadcrumb import Breadcrumb36from canonical.launchpad.webapp.breadcrumb import Breadcrumb
35from canonical.launchpad.helpers import shortlist37from canonical.launchpad.helpers import shortlist
@@ -38,6 +40,48 @@
38from canonical.lazr.utils import smartquote40from canonical.lazr.utils import smartquote
3941
4042
43class HasSpecificationsMenuMixin(object):
44
45 def listall(self):
46 """Return a link to show all blueprints."""
47 text = 'List all blueprints'
48 return Link('+specs?show=all', text, icon='blueprint')
49
50 def listaccepted(self):
51 """Return a link to show the approved goals."""
52 text = 'List approved blueprints'
53 return Link('+specs?acceptance=accepted', text, icon='blueprint')
54
55 def listproposed(self):
56 """Return a link to show the proposed goals."""
57 text = 'List proposed blueprints'
58 return Link('+specs?acceptance=proposed', text, icon='blueprint')
59
60 def listdeclined(self):
61 """Return a link to show the declined goals."""
62 text = 'List declined blueprints'
63 return Link('+specs?acceptance=declined', text, icon='blueprint')
64
65 def doc(self):
66 text = 'List documentation'
67 return Link('+documentation', text, icon='info')
68
69 def setgoals(self):
70 """Return a link to set the series goals."""
71 text = 'Set series goals'
72 return Link('+setgoals', text, icon='edit')
73
74 def assignments(self):
75 """Return a link to show the people assigned to the blueprint."""
76 text = 'Assignments'
77 return Link('+assignments', text, icon='person')
78
79 def new(self):
80 """Return a link to register a blueprint."""
81 text = 'Register a blueprint'
82 return Link('+addspec', text, icon='add')
83
84
41class HasSpecificationsView(LaunchpadView):85class HasSpecificationsView(LaunchpadView):
42 """Base class for several context-specific views that involve lists of86 """Base class for several context-specific views that involve lists of
43 specifications.87 specifications.
@@ -77,7 +121,6 @@
77 # replacing the conditional execution with polymorphism.121 # replacing the conditional execution with polymorphism.
78 # See https://bugs.launchpad.net/blueprint/+bug/173972.122 # See https://bugs.launchpad.net/blueprint/+bug/173972.
79 def initialize(self):123 def initialize(self):
80 mapping = {'name': self.context.displayname}
81 if IPerson.providedBy(self.context):124 if IPerson.providedBy(self.context):
82 self.is_person = True125 self.is_person = True
83 elif (IDistribution.providedBy(self.context) or126 elif (IDistribution.providedBy(self.context) or
@@ -104,11 +147,6 @@
104 else:147 else:
105 raise AssertionError, 'Unknown blueprint listing site'148 raise AssertionError, 'Unknown blueprint listing site'
106149
107 if self.is_person:
108 self.title = _('Specifications involving $name', mapping=mapping)
109 else:
110 self.title = _('Specifications for $name', mapping=mapping)
111
112 if IHasDrivers.providedBy(self.context):150 if IHasDrivers.providedBy(self.context):
113 self.has_drivers = True151 self.has_drivers = True
114152
@@ -116,6 +154,14 @@
116 self.specs, self.request,154 self.specs, self.request,
117 size=config.launchpad.default_batch_size)155 size=config.launchpad.default_batch_size)
118156
157 @property
158 def label(self):
159 mapping = {'name': self.context.displayname}
160 if self.is_person:
161 return _('Blueprints involving $name', mapping=mapping)
162 else:
163 return _('Blueprints for $name', mapping=mapping)
164
119 def mdzCsv(self):165 def mdzCsv(self):
120 """Quick hack for mdz, to get csv dump of specs."""166 """Quick hack for mdz, to get csv dump of specs."""
121 import csv167 import csv
@@ -313,8 +359,19 @@
313 quantity=quantity, prejoin_people=False)359 quantity=quantity, prejoin_people=False)
314360
315361
362class SpecificationAssignmentsView(HasSpecificationsView):
363 """View for +assignments pages."""
364 page_title = "Assignments"
365
366 @property
367 def label(self):
368 return smartquote(
369 'Blueprint assignments for "%s"' % self.context.displayname)
370
371
316class SpecificationDocumentationView(HasSpecificationsView):372class SpecificationDocumentationView(HasSpecificationsView):
317 """View for blueprints +documentation page."""373 """View for blueprints +documentation page."""
374 page_title = "Documentation"
318375
319 @property376 @property
320 def label(self):377 def label(self):
@@ -344,17 +401,7 @@
344 """ % canonical_url(target, rootsite='blueprints')401 """ % canonical_url(target, rootsite='blueprints')
345402
346403
347class HasSpecificationsOnBlueprintsVHostBreadcrumb(Breadcrumb):404class BlueprintsVHostBreadcrumb(Breadcrumb):
348 rootsite = 'blueprints'405 rootsite = 'blueprints'
349406 text = 'Blueprints'
350 @property407
351 def text(self):
352 return 'Blueprints for %s' % self.context.title
353
354
355class PersonOnBlueprintsVHostBreadcrumb(Breadcrumb):
356 rootsite = 'blueprints'
357
358 @property
359 def text(self):
360 return 'Blueprints involving %s' % self.context.displayname
361408
=== modified file 'lib/lp/blueprints/browser/sprint.py'
--- lib/lp/blueprints/browser/sprint.py 2009-09-21 12:39:15 +0000
+++ lib/lp/blueprints/browser/sprint.py 2009-09-22 15:02:41 +0000
@@ -46,7 +46,7 @@
4646
47from lp.app.interfaces.headings import IMajorHeadingView47from lp.app.interfaces.headings import IMajorHeadingView
48from lp.blueprints.browser.specificationtarget import (48from lp.blueprints.browser.specificationtarget import (
49 HasSpecificationsView)49 HasSpecificationsMenuMixin, HasSpecificationsView)
50from lp.blueprints.interfaces.specification import (50from lp.blueprints.interfaces.specification import (
51 SpecificationDefinitionStatus, SpecificationFilter, SpecificationPriority,51 SpecificationDefinitionStatus, SpecificationFilter, SpecificationPriority,
52 SpecificationSort)52 SpecificationSort)
@@ -110,32 +110,16 @@
110 return Link('+branding', text, summary, icon='edit')110 return Link('+branding', text, summary, icon='edit')
111111
112112
113class SprintSpecificationsMenu(ApplicationMenu):113class SprintSpecificationsMenu(NavigationMenu,
114114 HasSpecificationsMenuMixin):
115 usedfor = ISprint115 usedfor = ISprint
116 facet = 'specifications'116 facet = 'specifications'
117 links = ['assignments', 'declined', 'settopics', 'addspec']117 links = ['assignments', 'listdeclined', 'settopics', 'new']
118
119 def assignments(self):
120 text = 'Assignments'
121 summary = 'View the specification assignments'
122 return Link('+assignments', text, summary, icon='info')
123
124 def declined(self):
125 text = 'List declined blueprints'
126 summary = 'Show topics that were not accepted for discussion'
127 return Link('+specs?acceptance=declined', text, summary, icon='info')
128118
129 @enabled_with_permission('launchpad.Driver')119 @enabled_with_permission('launchpad.Driver')
130 def settopics(self):120 def settopics(self):
131 text = 'Set agenda'121 text = 'Set agenda'
132 summary = 'Approve or defer topics for discussion'122 return Link('+settopics', text, icon='edit')
133 return Link('+settopics', text, summary, icon='edit')
134
135 def addspec(self):
136 text = 'Register a blueprint'
137 summary = 'Register a new blueprint for this meeting'
138 return Link('+addspec', text, summary, icon='info')
139123
140124
141class SprintSetNavigation(GetitemNavigation):125class SprintSetNavigation(GetitemNavigation):
142126
=== modified file 'lib/lp/blueprints/browser/tests/test_breadcrumbs.py'
--- lib/lp/blueprints/browser/tests/test_breadcrumbs.py 2009-09-16 03:37:47 +0000
+++ lib/lp/blueprints/browser/tests/test_breadcrumbs.py 2009-09-22 15:02:41 +0000
@@ -29,16 +29,14 @@
29 self.product_specs_url, [self.root, self.product])29 self.product_specs_url, [self.root, self.product])
30 last_crumb = crumbs[-1]30 last_crumb = crumbs[-1]
31 self.assertEquals(last_crumb.url, self.product_specs_url)31 self.assertEquals(last_crumb.url, self.product_specs_url)
32 self.assertEquals(32 self.assertEquals(last_crumb.text, 'Blueprints')
33 last_crumb.text, 'Blueprints for %s' % self.product.title)
3433
35 def test_person(self):34 def test_person(self):
36 crumbs = self._getBreadcrumbs(35 crumbs = self._getBreadcrumbs(
37 self.person_specs_url, [self.root, self.person])36 self.person_specs_url, [self.root, self.person])
38 last_crumb = crumbs[-1]37 last_crumb = crumbs[-1]
39 self.assertEquals(last_crumb.url, self.person_specs_url)38 self.assertEquals(last_crumb.url, self.person_specs_url)
40 self.assertEquals(last_crumb.text,39 self.assertEquals(last_crumb.text, 'Blueprints')
41 'Blueprints involving %s' % self.person.displayname)
4240
4341
44class TestSpecificationBreadcrumb(BaseBreadcrumbTestCase):42class TestSpecificationBreadcrumb(BaseBreadcrumbTestCase):
4543
=== modified file 'lib/lp/blueprints/configure.zcml'
--- lib/lp/blueprints/configure.zcml 2009-09-16 03:37:47 +0000
+++ lib/lp/blueprints/configure.zcml 2009-09-22 15:02:41 +0000
@@ -236,12 +236,12 @@
236 name="blueprints"236 name="blueprints"
237 provides="canonical.launchpad.webapp.interfaces.IBreadcrumb"237 provides="canonical.launchpad.webapp.interfaces.IBreadcrumb"
238 for="lp.blueprints.interfaces.specificationtarget.IHasSpecifications"238 for="lp.blueprints.interfaces.specificationtarget.IHasSpecifications"
239 factory="lp.blueprints.browser.specificationtarget.HasSpecificationsOnBlueprintsVHostBreadcrumb"239 factory="lp.blueprints.browser.specificationtarget.BlueprintsVHostBreadcrumb"
240 permission="zope.Public"/>240 permission="zope.Public"/>
241 <adapter241 <adapter
242 name="blueprints"242 name="blueprints"
243 provides="canonical.launchpad.webapp.interfaces.IBreadcrumb"243 provides="canonical.launchpad.webapp.interfaces.IBreadcrumb"
244 for="lp.registry.interfaces.person.IPerson"244 for="lp.registry.interfaces.person.IPerson"
245 factory="lp.blueprints.browser.specificationtarget.PersonOnBlueprintsVHostBreadcrumb"245 factory="lp.blueprints.browser.specificationtarget.BlueprintsVHostBreadcrumb"
246 permission="zope.Public"/>246 permission="zope.Public"/>
247</configure>247</configure>
248248
=== modified file 'lib/lp/blueprints/stories/blueprints/01-creation.txt'
--- lib/lp/blueprints/stories/blueprints/01-creation.txt 2009-09-19 01:54:04 +0000
+++ lib/lp/blueprints/stories/blueprints/01-creation.txt 2009-09-22 15:02:41 +0000
@@ -64,7 +64,7 @@
64 ... user_browser.contents, 'menu-link-new'):64 ... user_browser.contents, 'menu-link-new'):
65 ... print tag65 ... print tag
66 <a href="http://blueprints.launchpad.dev/ubuntu/+addspec"66 <a href="http://blueprints.launchpad.dev/ubuntu/+addspec"
67 class="menu-link-new" ...>Register a blueprint</a>67 class="menu-link-new...>Register a blueprint</a>
6868
6969
70=== From a distribution series ===70=== From a distribution series ===
@@ -85,7 +85,7 @@
85 ... user_browser.contents, 'menu-link-new'):85 ... user_browser.contents, 'menu-link-new'):
86 ... print tag86 ... print tag
87 <a href="http://blueprints.launchpad.dev/ubuntu/hoary/+addspec"87 <a href="http://blueprints.launchpad.dev/ubuntu/hoary/+addspec"
88 class="menu-link-new" ...>Register a blueprint</a>88 class="menu-link-new...>Register a blueprint</a>
8989
9090
91=== From a product ===91=== From a product ===
@@ -106,7 +106,7 @@
106 ... user_browser.contents, 'menu-link-new'):106 ... user_browser.contents, 'menu-link-new'):
107 ... print tag107 ... print tag
108 <a href="http://blueprints.launchpad.dev/bzr/+addspec"108 <a href="http://blueprints.launchpad.dev/bzr/+addspec"
109 class="menu-link-new" ...>Register a blueprint</a>109 class="menu-link-new...>Register a blueprint</a>
110110
111For products without any blueprints, users can follow the special "register111For products without any blueprints, users can follow the special "register
112it here as a blueprint" link:112it here as a blueprint" link:
@@ -137,7 +137,7 @@
137 ... user_browser.contents, 'menu-link-new'):137 ... user_browser.contents, 'menu-link-new'):
138 ... print tag138 ... print tag
139 <a href="http://blueprints.launchpad.dev/firefox/1.0/+addspec"139 <a href="http://blueprints.launchpad.dev/firefox/1.0/+addspec"
140 class="menu-link-new" ...>Register a blueprint</a>140 class="menu-link-new...>Register a blueprint</a>
141141
142142
143=== From a project ===143=== From a project ===
@@ -158,7 +158,7 @@
158 ... user_browser.contents, 'menu-link-new'):158 ... user_browser.contents, 'menu-link-new'):
159 ... print tag159 ... print tag
160 <a href="http://blueprints.launchpad.dev/mozilla/+addspec"160 <a href="http://blueprints.launchpad.dev/mozilla/+addspec"
161 class="menu-link-new" ...>Register a blueprint</a>161 class="menu-link-new...>Register a blueprint</a>
162162
163163
164=== From a sprint ===164=== From a sprint ===
@@ -176,10 +176,10 @@
176Users can also follow the textual "Register a blueprint" link:176Users can also follow the textual "Register a blueprint" link:
177177
178 >>> for tag in find_tags_by_class(178 >>> for tag in find_tags_by_class(
179 ... user_browser.contents, 'menu-link-addspec'):179 ... user_browser.contents, 'menu-link-new'):
180 ... print tag180 ... print tag
181 <a href="http://blueprints.launchpad.dev/sprints/futurista/+addspec"181 <a href="http://blueprints.launchpad.dev/sprints/futurista/+addspec"
182 class="menu-link-addspec" ...>Register a blueprint</a>182 class="menu-link-new...>Register a blueprint</a>
183183
184184
185== Registering a blueprint ==185== Registering a blueprint ==
186186
=== modified file 'lib/lp/blueprints/stories/blueprints/07-milestones.txt'
--- lib/lp/blueprints/stories/blueprints/07-milestones.txt 2009-09-21 19:15:03 +0000
+++ lib/lp/blueprints/stories/blueprints/07-milestones.txt 2009-09-22 15:02:41 +0000
@@ -17,7 +17,7 @@
17 >>> admin_browser.getLink('Target milestone').click()17 >>> admin_browser.getLink('Target milestone').click()
18 >>> print admin_browser.title18 >>> print admin_browser.title
19 Target to a milestone : Support <canvas> Objects :19 Target to a milestone : Support <canvas> Objects :
20 Blueprints for Mozilla Firefox : Mozilla Firefox20 Blueprints : Mozilla Firefox
21 >>> back_link = admin_browser.getLink('Support <canvas> Objects')21 >>> back_link = admin_browser.getLink('Support <canvas> Objects')
22 >>> back_link.url22 >>> back_link.url
23 'http://blueprints.launchpad.dev/firefox/+spec/canvas'23 'http://blueprints.launchpad.dev/firefox/+spec/canvas'
2424
=== modified file 'lib/lp/blueprints/stories/blueprints/xx-overview.txt'
--- lib/lp/blueprints/stories/blueprints/xx-overview.txt 2009-09-21 19:15:03 +0000
+++ lib/lp/blueprints/stories/blueprints/xx-overview.txt 2009-09-22 15:02:41 +0000
@@ -44,6 +44,7 @@
44 >>> main = find_main_content(user_browser.contents)44 >>> main = find_main_content(user_browser.contents)
45 >>> print extract_text(main).encode('ascii', 'backslashreplace')45 >>> print extract_text(main).encode('ascii', 'backslashreplace')
46 Blueprints for 1.046 Blueprints for 1.0
47 ...
47 Launchpad lets projects track the features they intend to implement...48 Launchpad lets projects track the features they intend to implement...
4849
49Let's target an existing Mozilla Firefox blueprint to the 1.0 series:50Let's target an existing Mozilla Firefox blueprint to the 1.0 series:
@@ -144,6 +145,7 @@
144 >>> main = find_main_content(user_browser.contents)145 >>> main = find_main_content(user_browser.contents)
145 >>> print extract_text(main).encode('ascii', 'backslashreplace')146 >>> print extract_text(main).encode('ascii', 'backslashreplace')
146 Blueprints for Grumpy147 Blueprints for Grumpy
148 ...
147 Launchpad lets projects track the features they intend to implement...149 Launchpad lets projects track the features they intend to implement...
148150
149Let's target an existing Ubuntu blueprint to the Grumpy series:151Let's target an existing Ubuntu blueprint to the Grumpy series:
150152
=== modified file 'lib/lp/blueprints/stories/blueprints/xx-personviews.txt'
--- lib/lp/blueprints/stories/blueprints/xx-personviews.txt 2009-09-18 12:47:26 +0000
+++ lib/lp/blueprints/stories/blueprints/xx-personviews.txt 2009-09-22 15:02:41 +0000
@@ -8,8 +8,8 @@
8involving that person.8involving that person.
99
10 >>> browser.open('http://blueprints.launchpad.dev/~name16')10 >>> browser.open('http://blueprints.launchpad.dev/~name16')
11 >>> browser.title11 >>> print browser.title
12 'Blueprints involving Foo Bar'12 Blueprints : Foo Bar
13 >>> soup = find_main_content(browser.contents)13 >>> soup = find_main_content(browser.contents)
14 >>> soup('h1')14 >>> soup('h1')
15 [<h1>Blueprints involving Foo Bar</h1>]15 [<h1>Blueprints involving Foo Bar</h1>]
@@ -73,9 +73,10 @@
73are part of the workload for the team. It then shows the workloads73are part of the workload for the team. It then shows the workloads
74for each member of the team, using batching.74for each member of the team, using batching.
7575
76 >>> from canonical.launchpad.helpers import backslashreplace
76 >>> browser.open('http://blueprints.launchpad.dev/~admins')77 >>> browser.open('http://blueprints.launchpad.dev/~admins')
77 >>> browser.title78 >>> print backslashreplace(browser.title)
78 'Blueprints involving Launchpad Administrators'79 Blueprints : \u201cLaunchpad Administrators\u201d team
79 >>> browser.getLink('Workload').click()80 >>> browser.getLink('Workload').click()
80 >>> browser.url81 >>> browser.url
81 '.../~admins/+specworkload'82 '.../~admins/+specworkload'
8283
=== modified file 'lib/lp/blueprints/stories/sprints/15-sprint-tabular-view.txt'
--- lib/lp/blueprints/stories/sprints/15-sprint-tabular-view.txt 2009-05-11 18:19:21 +0000
+++ lib/lp/blueprints/stories/sprints/15-sprint-tabular-view.txt 2009-09-22 00:13:14 +0000
@@ -1,12 +1,12 @@
1We should be able to see the workload of a sprint:1We should be able to see the workload of a sprint:
22
3 >>> anon_browser.open('http://launchpad.dev/sprints/ubz/+assignments')3 >>> anon_browser.open('http://launchpad.dev/sprints/ubz/+assignments')
4 >>> anon_browser.title4 >>> print anon_browser.title
5 'Blueprint assignments for Ubuntu Below Zero'5 Assignments : Ubuntu Below Zero : Meetings
66
7We should be able to see the spec assignment table of a sprint:7We should be able to see the spec assignment table of a sprint:
88
9 >>> mainarea = find_tag_by_id(anon_browser.contents, 'mainarea')9 >>> mainarea = find_main_content(anon_browser.contents)
10 >>> for header in mainarea.findAll('th'):10 >>> for header in mainarea.findAll('th'):
11 ... print header.renderContents()11 ... print header.renderContents()
12 Priority12 Priority
@@ -21,6 +21,7 @@
21no spec assigned to people.21no spec assigned to people.
2222
23 >>> anon_browser.open('http://launchpad.dev/sprints/ltsponsteroids/+assignments')23 >>> anon_browser.open('http://launchpad.dev/sprints/ltsponsteroids/+assignments')
24 >>> 'No blueprints to display' in anon_browser.contents24 >>> notice = find_tag_by_id(anon_browser.contents, 'no-blueprints')
25 True25 >>> print extract_text(notice)
26 There are no open blueprints.
2627
2728
=== modified file 'lib/lp/blueprints/stories/sprints/sprint-settopics.txt'
--- lib/lp/blueprints/stories/sprints/sprint-settopics.txt 2009-09-21 12:43:33 +0000
+++ lib/lp/blueprints/stories/sprints/sprint-settopics.txt 2009-09-22 15:02:41 +0000
@@ -70,7 +70,7 @@
7070
71 >>> print cprov_browser.title71 >>> print cprov_browser.title
72 Review discussion topics for “Ubuntu DevSummit Guacamole” sprint :72 Review discussion topics for “Ubuntu DevSummit Guacamole” sprint :
73 Blueprints for Ubuntu DevSummit Guacamole :73 Blueprints :
74 Ubuntu DevSummit Guacamole :74 Ubuntu DevSummit Guacamole :
75 Meetings75 Meetings
7676
7777
=== modified file 'lib/lp/blueprints/templates/hasspecifications-specs.pt'
--- lib/lp/blueprints/templates/hasspecifications-specs.pt 2009-07-17 17:59:07 +0000
+++ lib/lp/blueprints/templates/hasspecifications-specs.pt 2009-09-22 15:02:41 +0000
@@ -3,18 +3,16 @@
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_side"
7 lang="en"
8 dir="ltr"
9 metal:use-macro="context/@@main_template/master"
10 i18n:domain="launchpad"7 i18n:domain="launchpad"
11>8>
129
13<body>10<body>
1411
15 <metal:portlets fill-slot="portlets">12<tal:side metal:fill-slot="side">
16 <div tal:replace="structure context/@@+portlet-latestspecs" />13 <tal:menu replace="structure context/@@+global-actions" />
17 </metal:portlets>14 <div tal:replace="structure context/@@+portlet-latestspecs" />
15</tal:side>
1816
19<div metal:fill-slot="main"17<div metal:fill-slot="main"
20 tal:define="specs view/specs;18 tal:define="specs view/specs;
@@ -33,11 +31,6 @@
33 </tal:block>31 </tal:block>
34 </tal:block>32 </tal:block>
3533
36 <h1 tal:condition="view/is_person"
37 >Blueprints involving <tal:person replace="context/title" /></h1>
38 <h1 tal:condition="not:view/is_person"
39 >Blueprints for <tal:software replace="context/displayname" /></h1>
40
41 <div style="float: right;"34 <div style="float: right;"
42 tal:content="structure context/@@+register-a-blueprint-button|nothing" />35 tal:content="structure context/@@+register-a-blueprint-button|nothing" />
4336
4437
=== modified file 'lib/lp/blueprints/templates/specificationtarget-assignments.pt'
--- lib/lp/blueprints/templates/specificationtarget-assignments.pt 2009-07-17 17:59:07 +0000
+++ lib/lp/blueprints/templates/specificationtarget-assignments.pt 2009-09-22 15:02:41 +0000
@@ -3,91 +3,95 @@
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_side"
7 lang="en"
8 dir="ltr"
9 metal:use-macro="context/@@main_template/master"
10 i18n:domain="launchpad"7 i18n:domain="launchpad"
11>8>
129
13<body>10<body>
1411
15<metal:leftportlets fill-slot="portlets_one">12<tal:side metal:fill-slot="side">
13 <tal:menu replace="structure context/@@+global-actions" />
16 <div tal:replace="structure context/@@+portlet-latestspecs" />14 <div tal:replace="structure context/@@+portlet-latestspecs" />
17</metal:leftportlets>15</tal:side>
18
19<metal:heading fill-slot="pageheading">
20 <h1>Assignment of work on blueprints</h1>
21</metal:heading>
2216
23<div metal:fill-slot="main">17<div metal:fill-slot="main">
2418
25 <p class="informational message" tal:condition="not: view/specs">19 <p class="portlet" tal:condition="not: view/specs" id="no-blueprints">
26 No blueprints to display.20 There are no open blueprints.
27 </p>21 </p>
2822
29 <table class="listing sortable" tal:condition="view/specs" id="work">23 <div tal:condition="view/specs" class="portlet">
30 <thead>24 <p>
31 <tr>25 This listing shows the assignment of work for
32 <th>Priority</th>26 blueprints currently associated with
33 <th>Name</th>27 <span tal:replace="context/displayname">Mozilla</span>.
34 <th>Definition</th>28 The drafter is responsible for getting the specification correctly
35 <th>Delivery</th>29 written up and approved.
36 <th>Assignee</th>30 The approver is usually the person who would
37 <th>Drafter</th>31 sign off on the specification.
38 <th>Approver</th>32 </p>
39 </tr>33
40 </thead>34 <table class="listing sortable" id="work">
41 <tbody class="lesser">35 <thead>
42 <tr tal:repeat="spec view/specs">36 <tr>
43 <td>37 <th>Priority</th>
44 <span class="sortkey" tal:content="spec/priority/sortkey" />38 <th>Name</th>
45 <span tal:content="spec/priority/title"39 <th>Definition</th>
46 tal:attributes="40 <th>Delivery</th>
47 class string:specpriority${spec/priority/name}">High</span>41 <th>Assignee</th>
48 </td>42 <th>Drafter</th>
49 <td><a tal:content="spec/name/fmt:shorten/35"43 <th>Approver</th>
50 tal:attributes="44 </tr>
51 href spec/fmt:url;45 </thead>
52 title spec/title">foo-bar-baz</a>46 <tbody class="lesser">
53 <img src="/@@/info" alt="Informational"47 <tr tal:repeat="spec view/specs">
54 tal:condition="spec/informational" />48 <td>
55 </td>49 <span class="sortkey" tal:content="spec/priority/sortkey" />
56 <td>50 <span tal:content="spec/priority/title"
57 <span class="sortkey" tal:content="spec/definition_status/sortkey" />51 tal:attributes="
58 <span tal:content="spec/definition_status/title"52 class string:specpriority${spec/priority/name}">High</span>
59 tal:attributes="53 </td>
60 class string:specstatus${spec/definition_status/name}">Approved</span>54 <td>
61 </td>55 <a tal:replace="structure spec/fmt:link">Better mousetrap</a>
62 <td>56 <span tal:condition="spec/informational"
63 <span class="sortkey" tal:content="spec/implementation_status/sortkey" />57 class="info sprite"
64 <span tal:content="spec/implementation_status/title"58 alt="Informational" />
65 tal:attributes="59 </td>
66 class string:specdelivery${spec/implementation_status/name}">Slow60 <td>
67 </span>61 <span class="sortkey" tal:content="spec/definition_status/sortkey" />
68 </td>62 <span tal:content="spec/definition_status/title"
69 <td><a tal:condition="spec/assignee"63 tal:attributes="
70 tal:content="spec/assignee/name"64 class string:specstatus${spec/definition_status/name}">Approved</span>
71 tal:attributes="href spec/assignee/fmt:url">Assignee Bar</a></td>65 </td>
72 <td><a tal:condition="spec/drafter"66 <td>
73 tal:content="spec/drafter/name"67 <span class="sortkey" tal:content="spec/implementation_status/sortkey" />
74 tal:attributes="href spec/drafter/fmt:url">Drafter Baz</a></td>68 <span tal:content="spec/implementation_status/title"
75 <td><a tal:condition="spec/approver"69 tal:attributes="
76 tal:content="spec/approver/name"70 class string:specdelivery${spec/implementation_status/name}">Slow
77 tal:attributes="href spec/approver/fmt:url">Approver Foo</a></td>71 </span>
78 </tr>72 </td>
79 </tbody>73 <td>
80 </table>74 <a tal:condition="spec/assignee"
8175 tal:replace="structure spec/assignee/fmt:link">
82 <p tal:condition="view/specs">76 Assignee Bar
83 This listing shows the assignment of work for77 </a>
84 blueprints currently associated with 78 </td>
85 <span tal:replace="context/displayname">Mozilla</span>.79 <td>
86 The drafter is responsible for getting the specification correctly80 <a tal:condition="spec/drafter"
87 written up and approved.81 tal:replace="structure spec/drafter/fmt:link">
88 The approver is usually the person who would82 Drafter Baz
89 sign off on the specification.83 </a>
90 </p>84 </td>
85 <td>
86 <a tal:condition="spec/approver"
87 tal:replace="structure spec/approver/fmt:link">
88 Approver Foo
89 </a>
90 </td>
91 </tr>
92 </tbody>
93 </table>
94 </div>
9195
92</div>96</div>
93</body>97</body>
9498
=== modified file 'lib/lp/registry/browser/distribution.py'
--- lib/lp/registry/browser/distribution.py 2009-09-16 00:40:53 +0000
+++ lib/lp/registry/browser/distribution.py 2009-09-22 15:02:41 +0000
@@ -47,6 +47,8 @@
47from zope.security.interfaces import Unauthorized47from zope.security.interfaces import Unauthorized
4848
49from canonical.cachedproperty import cachedproperty49from canonical.cachedproperty import cachedproperty
50from lp.blueprints.browser.specificationtarget import (
51 HasSpecificationsMenuMixin)
50from lp.registry.browser.announcement import HasAnnouncementsView52from lp.registry.browser.announcement import HasAnnouncementsView
51from lp.registry.browser.menu import (53from lp.registry.browser.menu import (
52 IRegistryCollectionNavigationMenu, RegistryCollectionActionMenuBase)54 IRegistryCollectionNavigationMenu, RegistryCollectionActionMenuBase)
@@ -454,31 +456,12 @@
454 return Link('+subscribe', text, icon='edit')456 return Link('+subscribe', text, icon='edit')
455457
456458
457class DistributionSpecificationsMenu(ApplicationMenu):459class DistributionSpecificationsMenu(NavigationMenu,
458460 HasSpecificationsMenuMixin):
459 usedfor = IDistribution461 usedfor = IDistribution
460 facet = 'specifications'462 facet = 'specifications'
461 links = ['listall', 'doc', 'assignments', 'new']463 links = ['listall', 'doc', 'assignments', 'new']
462464
463 def listall(self):
464 text = 'List all blueprints'
465 return Link('+specs?show=all', text, icon='info')
466
467 def assignments(self):
468 text = 'Assignments'
469 return Link('+assignments', text, icon='info')
470
471 def doc(self):
472 text = 'Documentation'
473 summary = 'List all complete informational specifications'
474 return Link('+documentation', text, summary,
475 icon='info')
476
477 def new(self):
478 text = 'Register a blueprint'
479 summary = 'Register a new blueprint for %s' % self.context.title
480 return Link('+addspec', text, summary, icon='add')
481
482465
483class DistributionPackageSearchView(PackageSearchViewBase):466class DistributionPackageSearchView(PackageSearchViewBase):
484 """Customised PackageSearchView for Distribution"""467 """Customised PackageSearchView for Distribution"""
485468
=== modified file 'lib/lp/registry/browser/distroseries.py'
--- lib/lp/registry/browser/distroseries.py 2009-09-15 01:17:46 +0000
+++ lib/lp/registry/browser/distroseries.py 2009-09-22 15:02:41 +0000
@@ -28,6 +28,8 @@
28from canonical.database.constants import UTC_NOW28from canonical.database.constants import UTC_NOW
29from canonical.launchpad import _29from canonical.launchpad import _
30from canonical.launchpad import helpers30from canonical.launchpad import helpers
31from lp.blueprints.browser.specificationtarget import (
32 HasSpecificationsMenuMixin)
31from lp.bugs.browser.bugtask import BugTargetTraversalMixin33from lp.bugs.browser.bugtask import BugTargetTraversalMixin
32from lp.soyuz.browser.build import BuildRecordsView34from lp.soyuz.browser.build import BuildRecordsView
33from canonical.launchpad.browser.packagesearch import PackageSearchViewBase35from canonical.launchpad.browser.packagesearch import PackageSearchViewBase
@@ -49,7 +51,7 @@
49from canonical.launchpad.webapp.launchpadform import (51from canonical.launchpad.webapp.launchpadform import (
50 LaunchpadEditFormView, LaunchpadFormView)52 LaunchpadEditFormView, LaunchpadFormView)
51from canonical.launchpad.webapp.menu import (53from canonical.launchpad.webapp.menu import (
52 ApplicationMenu, Link, enabled_with_permission)54 ApplicationMenu, Link, NavigationMenu, enabled_with_permission)
53from canonical.launchpad.webapp.publisher import (55from canonical.launchpad.webapp.publisher import (
54 canonical_url, stepthrough, stepto)56 canonical_url, stepthrough, stepto)
55from canonical.widgets.itemswidgets import LaunchpadDropdownWidget57from canonical.widgets.itemswidgets import LaunchpadDropdownWidget
@@ -225,43 +227,12 @@
225 return Link('+subscribe', 'Subscribe to bug mail')227 return Link('+subscribe', 'Subscribe to bug mail')
226228
227229
228class DistroSeriesSpecificationsMenu(ApplicationMenu):230class DistroSeriesSpecificationsMenu(NavigationMenu,
231 HasSpecificationsMenuMixin):
229232
230 usedfor = IDistroSeries233 usedfor = IDistroSeries
231 facet = 'specifications'234 facet = 'specifications'
232 links = ['listall', 'table', 'setgoals', 'listdeclined', 'new']235 links = ['listall', 'listdeclined', 'assignments', 'setgoals', 'new']
233
234 def listall(self):
235 text = 'List all blueprints'
236 return Link('+specs?show=all', text, icon='info')
237
238 def listapproved(self):
239 text = 'List approved blueprints'
240 return Link('+specs?acceptance=accepted', text, icon='info')
241
242 def listproposed(self):
243 text = 'List proposed blueprints'
244 return Link('+specs?acceptance=proposed', text, icon='info')
245
246 def listdeclined(self):
247 text = 'List declined blueprints'
248 summary = 'Show the goals which have been declined'
249 return Link('+specs?acceptance=declined', text, icon='info')
250
251 def setgoals(self):
252 text = 'Set series goals'
253 summary = 'Approve or decline feature goals that have been proposed'
254 return Link('+setgoals', text, icon='info')
255
256 def table(self):
257 text = 'Assignments'
258 summary = 'Show the assignee, drafter and approver of these specs'
259 return Link('+assignments', text, icon='info')
260
261 def new(self):
262 text = 'Register a blueprint'
263 summary = 'Register a new blueprint for %s' % self.context.title
264 return Link('+addspec', text, summary, icon='add')
265236
266237
267class DistroSeriesPackageSearchView(PackageSearchViewBase):238class DistroSeriesPackageSearchView(PackageSearchViewBase):
268239
=== modified file 'lib/lp/registry/browser/person.py'
--- lib/lp/registry/browser/person.py 2009-09-20 07:13:52 +0000
+++ lib/lp/registry/browser/person.py 2009-09-22 15:02:41 +0000
@@ -775,7 +775,7 @@
775 return Link('+commentedbugs', text, summary=summary)775 return Link('+commentedbugs', text, summary=summary)
776776
777777
778class PersonSpecsMenu(ApplicationMenu):778class PersonSpecsMenu(NavigationMenu):
779779
780 usedfor = IPerson780 usedfor = IPerson
781 facet = 'specifications'781 facet = 'specifications'
@@ -786,28 +786,28 @@
786 def registrant(self):786 def registrant(self):
787 text = 'Registrant'787 text = 'Registrant'
788 summary = 'List specs registered by %s' % self.context.displayname788 summary = 'List specs registered by %s' % self.context.displayname
789 return Link('+specs?role=registrant', text, summary, icon='spec')789 return Link('+specs?role=registrant', text, summary, icon='blueprint')
790790
791 def approver(self):791 def approver(self):
792 text = 'Approver'792 text = 'Approver'
793 summary = 'List specs with %s is supposed to approve' % (793 summary = 'List specs with %s is supposed to approve' % (
794 self.context.displayname)794 self.context.displayname)
795 return Link('+specs?role=approver', text, summary, icon='spec')795 return Link('+specs?role=approver', text, summary, icon='blueprint')
796796
797 def assignee(self):797 def assignee(self):
798 text = 'Assignee'798 text = 'Assignee'
799 summary = 'List specs for which %s is the assignee' % (799 summary = 'List specs for which %s is the assignee' % (
800 self.context.displayname)800 self.context.displayname)
801 return Link('+specs?role=assignee', text, summary, icon='spec')801 return Link('+specs?role=assignee', text, summary, icon='blueprint')
802802
803 def drafter(self):803 def drafter(self):
804 text = 'Drafter'804 text = 'Drafter'
805 summary = 'List specs drafted by %s' % self.context.displayname805 summary = 'List specs drafted by %s' % self.context.displayname
806 return Link('+specs?role=drafter', text, summary, icon='spec')806 return Link('+specs?role=drafter', text, summary, icon='blueprint')
807807
808 def subscriber(self):808 def subscriber(self):
809 text = 'Subscriber'809 text = 'Subscriber'
810 return Link('+specs?role=subscriber', text, icon='spec')810 return Link('+specs?role=subscriber', text, icon='blueprint')
811811
812 def feedback(self):812 def feedback(self):
813 text = 'Feedback requests'813 text = 'Feedback requests'
814814
=== modified file 'lib/lp/registry/browser/product.py'
--- lib/lp/registry/browser/product.py 2009-09-18 01:34:06 +0000
+++ lib/lp/registry/browser/product.py 2009-09-22 15:02:41 +0000
@@ -58,6 +58,8 @@
58from canonical.launchpad import _58from canonical.launchpad import _
59from canonical.launchpad.fields import PillarAliases, PublicPersonChoice59from canonical.launchpad.fields import PillarAliases, PublicPersonChoice
60from lp.app.interfaces.headings import IEditableContextTitle60from lp.app.interfaces.headings import IEditableContextTitle
61from lp.blueprints.browser.specificationtarget import (
62 HasSpecificationsMenuMixin)
61from lp.bugs.interfaces.bugtask import RESOLVED_BUGTASK_STATUSES63from lp.bugs.interfaces.bugtask import RESOLVED_BUGTASK_STATUSES
62from lp.bugs.interfaces.bugwatch import IBugTracker64from lp.bugs.interfaces.bugwatch import IBugTracker
63from lp.services.worlddata.interfaces.country import ICountry65from lp.services.worlddata.interfaces.country import ICountry
@@ -475,32 +477,11 @@
475 return Link('+subscribe', text, icon='edit')477 return Link('+subscribe', text, icon='edit')
476478
477479
478class ProductSpecificationsMenu(ApplicationMenu):480class ProductSpecificationsMenu(NavigationMenu,
479481 HasSpecificationsMenuMixin):
480 usedfor = IProduct482 usedfor = IProduct
481 facet = 'specifications'483 facet = 'specifications'
482 links = ['listall', 'doc', 'table', 'new']484 links = ['listall', 'doc', 'assignments', 'new']
483
484 def listall(self):
485 text = 'List all blueprints'
486 summary = 'Show all specifications for %s' % self.context.title
487 return Link('+specs?show=all', text, summary, icon='info')
488
489 def doc(self):
490 text = 'List documentation'
491 summary = 'List all complete informational specifications'
492 return Link('+documentation', text, summary,
493 icon='info')
494
495 def table(self):
496 text = 'Assignments'
497 summary = 'Show the full assignment of work, drafting and approving'
498 return Link('+assignments', text, summary, icon='info')
499
500 def new(self):
501 text = 'Register a blueprint'
502 summary = 'Register a new blueprint for %s' % self.context.title
503 return Link('+addspec', text, summary, icon='add')
504485
505486
506def _sort_distros(a, b):487def _sort_distros(a, b):
507488
=== modified file 'lib/lp/registry/browser/productseries.py'
--- lib/lp/registry/browser/productseries.py 2009-09-15 02:16:19 +0000
+++ lib/lp/registry/browser/productseries.py 2009-09-22 15:02:41 +0000
@@ -39,6 +39,8 @@
39from canonical.cachedproperty import cachedproperty39from canonical.cachedproperty import cachedproperty
40from canonical.launchpad import _40from canonical.launchpad import _
41from lp.code.browser.branchref import BranchRef41from lp.code.browser.branchref import BranchRef
42from lp.blueprints.browser.specificationtarget import (
43 HasSpecificationsMenuMixin)
42from lp.blueprints.interfaces.specification import (44from lp.blueprints.interfaces.specification import (
43 ISpecificationSet, SpecificationImplementationStatus)45 ISpecificationSet, SpecificationImplementationStatus)
44from lp.bugs.interfaces.bugtask import BugTaskStatus46from lp.bugs.interfaces.bugtask import BugTaskStatus
@@ -247,7 +249,8 @@
247 return Link('+subscribe', 'Subscribe to bug mail')249 return Link('+subscribe', 'Subscribe to bug mail')
248250
249251
250class ProductSeriesSpecificationsMenu(ApplicationMenu):252class ProductSeriesSpecificationsMenu(NavigationMenu,
253 HasSpecificationsMenuMixin):
251 """Specs menu for ProductSeries.254 """Specs menu for ProductSeries.
252255
253 This menu needs to keep track of whether we are showing all the256 This menu needs to keep track of whether we are showing all the
@@ -258,46 +261,7 @@
258261
259 usedfor = IProductSeries262 usedfor = IProductSeries
260 facet = 'specifications'263 facet = 'specifications'
261 links = ['listall', 'table', 'setgoals', 'listdeclined', 'new']264 links = ['listall', 'assignments', 'setgoals', 'listdeclined', 'new']
262
263 def listall(self):
264 """Return a link to show all blueprints."""
265 text = 'List all blueprints'
266 return Link('+specs?show=all', text, icon='info')
267
268 def listaccepted(self):
269 """Return a link to show the approved goals."""
270 text = 'List approved blueprints'
271 return Link('+specs?acceptance=accepted', text, icon='info')
272
273 def listproposed(self):
274 """Return a link to show the proposed goals."""
275 text = 'List proposed blueprints'
276 return Link('+specs?acceptance=proposed', text, icon='info')
277
278 def listdeclined(self):
279 """Return a link to show the declined goals."""
280 text = 'List declined blueprints'
281 summary = 'Show the goals which have been declined'
282 return Link('+specs?acceptance=declined', text, summary, icon='info')
283
284 def setgoals(self):
285 """Return a link to set the series goals."""
286 text = 'Set series goals'
287 summary = 'Approve or decline feature goals that have been proposed'
288 return Link('+setgoals', text, summary, icon='edit')
289
290 def table(self):
291 """Return a link to show the people assigned to the blueprint."""
292 text = 'Assignments'
293 summary = 'Show the assignee, drafter and approver of these specs'
294 return Link('+assignments', text, summary, icon='info')
295
296 def new(self):
297 """Return a link to register a blueprint."""
298 text = 'Register a blueprint'
299 summary = 'Register a new blueprint for %s' % self.context.title
300 return Link('+addspec', text, summary, icon='add')
301265
302266
303class ProductSeriesOverviewNavigationMenu(NavigationMenu):267class ProductSeriesOverviewNavigationMenu(NavigationMenu):
304268
=== modified file 'lib/lp/registry/browser/project.py'
--- lib/lp/registry/browser/project.py 2009-09-15 20:41:36 +0000
+++ lib/lp/registry/browser/project.py 2009-09-22 15:02:41 +0000
@@ -44,6 +44,8 @@
44from canonical.launchpad import _44from canonical.launchpad import _
45from canonical.launchpad.webapp.interfaces import NotFoundError45from canonical.launchpad.webapp.interfaces import NotFoundError
46from canonical.launchpad.webapp.menu import NavigationMenu46from canonical.launchpad.webapp.menu import NavigationMenu
47from lp.blueprints.browser.specificationtarget import (
48 HasSpecificationsMenuMixin)
47from lp.registry.interfaces.product import IProductSet49from lp.registry.interfaces.product import IProductSet
48from lp.registry.interfaces.project import (50from lp.registry.interfaces.project import (
49 IProject, IProjectSeries, IProjectSet)51 IProject, IProjectSeries, IProjectSet)
@@ -267,30 +269,12 @@
267 links = ('branding', 'reassign', 'driver', 'administer')269 links = ('branding', 'reassign', 'driver', 'administer')
268270
269271
270class ProjectSpecificationsMenu(ApplicationMenu):272class ProjectSpecificationsMenu(NavigationMenu,
271273 HasSpecificationsMenuMixin):
272 usedfor = IProject274 usedfor = IProject
273 facet = 'specifications'275 facet = 'specifications'
274 links = ['listall', 'doc', 'assignments', 'new']276 links = ['listall', 'doc', 'assignments', 'new']
275277
276 def listall(self):
277 text = 'List all blueprints'
278 return Link('+specs?show=all', text, icon='info')
279
280 def doc(self):
281 text = 'List documentation'
282 summary = 'Show all completed informational specifications'
283 return Link('+documentation', text, summary, icon="info")
284
285 def assignments(self):
286 text = 'Assignments'
287 return Link('+assignments', text, icon='info')
288
289 def new(self):
290 text = 'Register a blueprint'
291 summary = 'Register a new blueprint for %s' % self.context.title
292 return Link('+addspec', text, summary, icon='add')
293
294278
295class ProjectAnswersMenu(QuestionCollectionAnswersMenu):279class ProjectAnswersMenu(QuestionCollectionAnswersMenu):
296 """Menu for the answers facet of projects."""280 """Menu for the answers facet of projects."""