Merge lp://qastaging/~sinzui/launchpad/blueprints-ui into lp://qastaging/launchpad
- blueprints-ui
- Merge into devel
Proposed by
Curtis Hovey
Status: | Merged | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Merged at revision: | not available | ||||||||||||||||
Proposed branch: | lp://qastaging/~sinzui/launchpad/blueprints-ui | ||||||||||||||||
Merge into: | lp://qastaging/launchpad | ||||||||||||||||
Diff against target: |
1065 lines (+307/-189) 28 files modified
lib/canonical/launchpad/pagetitles.py (+0/-2) lib/lp/blueprints/browser/configure.zcml (+2/-0) lib/lp/blueprints/browser/specification.py (+44/-48) lib/lp/blueprints/browser/specificationtarget.py (+32/-12) lib/lp/blueprints/browser/sprint.py (+16/-3) lib/lp/blueprints/browser/tests/test_menus.py (+40/-0) lib/lp/blueprints/browser/tests/test_specificationtarget.py (+93/-0) lib/lp/blueprints/stories/blueprints/01-creation.txt (+5/-32) lib/lp/blueprints/stories/blueprints/02-buglinks.txt (+1/-1) lib/lp/blueprints/stories/sprints/05-sprint-creation.txt (+2/-1) lib/lp/blueprints/stories/standalone/subscribing.txt (+2/-2) lib/lp/blueprints/templates/hasspecifications-specs.pt (+14/-19) lib/lp/blueprints/templates/specification-index.pt (+1/-13) lib/lp/blueprints/templates/specificationtarget-documentation.pt (+3/-4) lib/lp/blueprints/templates/sprint-portlet-attendees.pt (+1/-1) lib/lp/blueprints/templates/sprint-register.pt (+4/-0) lib/lp/bugs/browser/buglinktarget.py (+7/-16) lib/lp/bugs/browser/tests/buglinktarget-views.txt (+20/-4) lib/lp/coop/answersbugs/stories/question-buglink.txt (+1/-1) lib/lp/registry/browser/distribution.py (+1/-1) lib/lp/registry/browser/distroseries.py (+3/-1) lib/lp/registry/browser/person.py (+1/-0) lib/lp/registry/browser/product.py (+1/-1) lib/lp/registry/browser/productseries.py (+3/-1) lib/lp/registry/browser/project.py (+1/-1) lib/lp/registry/browser/tests/product-menus.txt (+3/-23) lib/lp/testing/factory.py (+3/-2) lib/lp/testing/menu.py (+3/-0) |
||||||||||||||||
To merge this branch: | bzr merge lp://qastaging/~sinzui/launchpad/blueprints-ui | ||||||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Graham Binns (community) | code | Approve | |
Martin Albisetti | ui | Pending | |
Review via email: mp+14639@code.qastaging.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Curtis Hovey (sinzui) wrote : | # |
Revision history for this message
Graham Binns (gmb) wrote : | # |
Code looks good to me. You should get a UI review too, though.
review:
Approve
(code)
Revision history for this message
Curtis Hovey (sinzui) wrote : | # |
This branch fixes the /sprints menus:
http://
This branch replaces the 1.0 register a sprint button with a involvement-style
porlet as is done on the bugs pages
http://
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'lib/canonical/launchpad/pagetitles.py' |
2 | --- lib/canonical/launchpad/pagetitles.py 2009-10-16 13:20:48 +0000 |
3 | +++ lib/canonical/launchpad/pagetitles.py 2009-11-14 04:37:12 +0000 |
4 | @@ -800,8 +800,6 @@ |
5 | |
6 | sprint_edit = ContextTitle(smartquote('Edit "%s" details')) |
7 | |
8 | -sprint_index = ContextTitle('%s (sprint or meeting)') |
9 | - |
10 | sprint_new = 'Register a meeting or sprint in Launchpad' |
11 | |
12 | sprint_specs = ContextTitle('Blueprints for %s') |
13 | |
14 | === modified file 'lib/lp/blueprints/browser/configure.zcml' |
15 | --- lib/lp/blueprints/browser/configure.zcml 2009-09-22 19:52:18 +0000 |
16 | +++ lib/lp/blueprints/browser/configure.zcml 2009-11-14 04:37:13 +0000 |
17 | @@ -110,6 +110,7 @@ |
18 | <browser:page |
19 | name="+addspec" |
20 | for="lp.blueprints.interfaces.sprint.ISprint" |
21 | + facet="specifications" |
22 | class="lp.blueprints.browser.specification.NewSpecificationFromSprintView" |
23 | permission="launchpad.AnyPerson" |
24 | template="../../app/templates/generic-edit.pt"/> |
25 | @@ -235,6 +236,7 @@ |
26 | <browser:menus |
27 | module="lp.blueprints.browser.specification" |
28 | classes=" |
29 | + SpecificationActionMenu |
30 | SpecificationContextMenu"/> |
31 | <browser:navigation |
32 | module="lp.blueprints.browser.specification" |
33 | |
34 | === modified file 'lib/lp/blueprints/browser/specification.py' |
35 | --- lib/lp/blueprints/browser/specification.py 2009-09-22 16:42:19 +0000 |
36 | +++ lib/lp/blueprints/browser/specification.py 2009-11-14 04:37:13 +0000 |
37 | @@ -13,6 +13,7 @@ |
38 | 'NewSpecificationFromProjectView', |
39 | 'NewSpecificationFromRootView', |
40 | 'NewSpecificationFromSprintView', |
41 | + 'SpecificationActionMenu', |
42 | 'SpecificationContextMenu', |
43 | 'SpecificationNavigation', |
44 | 'SpecificationView', |
45 | @@ -71,12 +72,12 @@ |
46 | HasSpecificationsView) |
47 | |
48 | from canonical.launchpad.webapp import ( |
49 | - ContextMenu, LaunchpadView, LaunchpadEditFormView, LaunchpadFormView, |
50 | - Link, Navigation, action, canonical_url, enabled_with_permission, |
51 | + LaunchpadView, LaunchpadEditFormView, LaunchpadFormView, |
52 | + Navigation, action, canonical_url, |
53 | safe_action, stepthrough, stepto, custom_widget) |
54 | from canonical.launchpad.webapp.authorization import check_permission |
55 | -from canonical.launchpad.webapp.interfaces import ILaunchBag |
56 | -from lp.registry.browser.mentoringoffer import CanBeMentoredView |
57 | +from canonical.launchpad.webapp.menu import ( |
58 | + ContextMenu, enabled_with_permission, Link, NavigationMenu) |
59 | from canonical.launchpad.browser.launchpad import AppFrontPageSearchView |
60 | |
61 | |
62 | @@ -272,7 +273,32 @@ |
63 | return self.context.getSprintSpecification(name) |
64 | |
65 | |
66 | -class SpecificationContextMenu(ContextMenu): |
67 | +class SpecificationEditLinksMixin: |
68 | + |
69 | + @enabled_with_permission('launchpad.Edit') |
70 | + def edit(self): |
71 | + text = 'Change details' |
72 | + return Link('+edit', text, icon='edit') |
73 | + |
74 | + @enabled_with_permission('launchpad.Edit') |
75 | + def supersede(self): |
76 | + text = 'Mark superseded' |
77 | + return Link('+supersede', text, icon='edit') |
78 | + |
79 | + @enabled_with_permission('launchpad.Edit') |
80 | + def retarget(self): |
81 | + text = 'Re-target blueprint' |
82 | + return Link('+retarget', text, icon='edit') |
83 | + |
84 | + |
85 | +class SpecificationActionMenu(NavigationMenu, SpecificationEditLinksMixin): |
86 | + |
87 | + usedfor = ISpecification |
88 | + facet = 'specifications' |
89 | + links = ('edit', 'supersede', 'retarget') |
90 | + |
91 | + |
92 | +class SpecificationContextMenu(ContextMenu, SpecificationEditLinksMixin): |
93 | |
94 | usedfor = ISpecification |
95 | links = ['edit', 'people', 'status', 'priority', |
96 | @@ -280,16 +306,10 @@ |
97 | 'milestone', 'requestfeedback', 'givefeedback', 'subscription', |
98 | 'subscribeanother', |
99 | 'linkbug', 'unlinkbug', 'linkbranch', |
100 | - 'offermentoring', 'retractmentoring', |
101 | 'adddependency', 'removedependency', |
102 | 'dependencytree', 'linksprint', 'supersede', |
103 | 'retarget'] |
104 | |
105 | - @enabled_with_permission('launchpad.Edit') |
106 | - def edit(self): |
107 | - text = 'Change details' |
108 | - return Link('+edit', text, icon='edit') |
109 | - |
110 | def givefeedback(self): |
111 | text = 'Give feedback' |
112 | enabled = (self.user is not None and |
113 | @@ -306,7 +326,7 @@ |
114 | text = 'Change people' |
115 | return Link('+people', text, icon='edit') |
116 | |
117 | - @enabled_with_permission('launchpad.Edit') |
118 | + @enabled_with_permission('launchpad.Admin') |
119 | def priority(self): |
120 | text = 'Change priority' |
121 | return Link('+priority', text, icon='edit') |
122 | @@ -335,24 +355,6 @@ |
123 | text = 'Change status' |
124 | return Link('+status', text, icon='edit') |
125 | |
126 | - @enabled_with_permission('launchpad.AnyPerson') |
127 | - def offermentoring(self): |
128 | - text = 'Offer mentorship' |
129 | - user = getUtility(ILaunchBag).user |
130 | - enabled = self.context.canMentor(user) |
131 | - return Link('+mentor', text, icon='add', enabled=enabled) |
132 | - |
133 | - def retractmentoring(self): |
134 | - text = 'Retract mentorship' |
135 | - user = getUtility(ILaunchBag).user |
136 | - # We should really only allow people to retract mentoring if the |
137 | - # spec's open and the user's already a mentor. |
138 | - if user and not self.context.is_complete: |
139 | - enabled = self.context.isMentor(user) |
140 | - else: |
141 | - enabled = False |
142 | - return Link('+retractmentoring', text, icon='remove', enabled=enabled) |
143 | - |
144 | def subscribeanother(self): |
145 | """Return the 'Subscribe someone else' Link.""" |
146 | text = 'Subscribe someone else' |
147 | @@ -372,16 +374,12 @@ |
148 | icon = 'add' |
149 | return Link('+subscribe', text, icon=icon) |
150 | |
151 | - @enabled_with_permission('launchpad.Edit') |
152 | - def supersede(self): |
153 | - text = 'Mark superseded' |
154 | - return Link('+supersede', text, icon='edit') |
155 | - |
156 | @enabled_with_permission('launchpad.AnyPerson') |
157 | def linkbug(self): |
158 | text = 'Link a bug report' |
159 | return Link('+linkbug', text, icon='add') |
160 | |
161 | + @enabled_with_permission('launchpad.AnyPerson') |
162 | def unlinkbug(self): |
163 | text = 'Unlink a bug' |
164 | enabled = bool(self.context.bugs) |
165 | @@ -409,11 +407,6 @@ |
166 | text = 'Propose for sprint' |
167 | return Link('+linksprint', text, icon='add') |
168 | |
169 | - @enabled_with_permission('launchpad.Edit') |
170 | - def retarget(self): |
171 | - text = 'Re-target blueprint' |
172 | - return Link('+retarget', text, icon='edit') |
173 | - |
174 | @enabled_with_permission('launchpad.AnyPerson') |
175 | def whiteboard(self): |
176 | text = 'Edit whiteboard' |
177 | @@ -427,7 +420,8 @@ |
178 | text = 'Link a related branch' |
179 | return Link('+linkbranch', text, icon='add') |
180 | |
181 | -class SpecificationSimpleView(LaunchpadView, CanBeMentoredView): |
182 | + |
183 | +class SpecificationSimpleView(LaunchpadView): |
184 | """Used to render portlets and listing items that need browser code.""" |
185 | |
186 | __used_for__ = ISpecification |
187 | @@ -489,16 +483,18 @@ |
188 | essential = request.form.get('essential') == 'yes' |
189 | if sub is not None: |
190 | self.context.subscribe(self.user, self.user, essential) |
191 | - self.notices.append("You have subscribed to this spec.") |
192 | + self.notices.append( |
193 | + "You have subscribed to this blueprint.") |
194 | elif upd is not None: |
195 | self.context.subscribe(self.user, self.user, essential) |
196 | self.notices.append('Your subscription has been updated.') |
197 | elif unsub is not None: |
198 | self.context.unsubscribe(self.user) |
199 | - self.notices.append("You have unsubscribed from this spec.") |
200 | + self.notices.append( |
201 | + "You have unsubscribed from this blueprint.") |
202 | |
203 | if self.feedbackrequests: |
204 | - msg = "You have %d feedback request(s) on this specification." |
205 | + msg = "You have %d feedback request(s) on this blueprint." |
206 | msg %= len(self.feedbackrequests) |
207 | self.notices.append(msg) |
208 | |
209 | @@ -529,7 +525,7 @@ |
210 | newstate = self.context.updateLifecycleStatus(self.user) |
211 | if newstate is not None: |
212 | self.request.response.addNotification( |
213 | - 'Specification is now considered "%s".' % newstate.title) |
214 | + 'blueprint is now considered "%s".' % newstate.title) |
215 | self.next_url = canonical_url(self.context) |
216 | |
217 | |
218 | @@ -693,7 +689,7 @@ |
219 | elif IDistribution.providedBy(target): |
220 | distribution = target |
221 | else: |
222 | - raise AssertionError, 'Unknown target' |
223 | + raise AssertionError('Unknown target.') |
224 | self.context.retarget(product=product, distribution=distribution) |
225 | self._nextURL = canonical_url(self.context) |
226 | |
227 | @@ -747,8 +743,8 @@ |
228 | vocabulary=SimpleVocabulary(terms), |
229 | required=False, |
230 | description=_( |
231 | - "The specification which supersedes this one. Note " |
232 | - "that selecting a specification here and pressing " |
233 | + "The blueprint which supersedes this one. Note " |
234 | + "that selecting a blueprint here and pressing " |
235 | "Continue will change the specification status " |
236 | "to Superseded.")), |
237 | render_context=self.render_context) |
238 | |
239 | === modified file 'lib/lp/blueprints/browser/specificationtarget.py' |
240 | --- lib/lp/blueprints/browser/specificationtarget.py 2009-09-22 15:02:41 +0000 |
241 | +++ lib/lp/blueprints/browser/specificationtarget.py 2009-11-14 04:37:12 +0000 |
242 | @@ -31,9 +31,10 @@ |
243 | |
244 | from canonical.config import config |
245 | from canonical.launchpad import _ |
246 | -from canonical.launchpad.webapp import LaunchpadView, Link |
247 | +from canonical.launchpad.webapp import LaunchpadView |
248 | from canonical.launchpad.webapp.batching import BatchNavigator |
249 | from canonical.launchpad.webapp.breadcrumb import Breadcrumb |
250 | +from canonical.launchpad.webapp.menu import enabled_with_permission, Link |
251 | from canonical.launchpad.helpers import shortlist |
252 | from canonical.cachedproperty import cachedproperty |
253 | from canonical.launchpad.webapp import canonical_url |
254 | @@ -81,6 +82,12 @@ |
255 | text = 'Register a blueprint' |
256 | return Link('+addspec', text, icon='add') |
257 | |
258 | + @enabled_with_permission('launchpad.View') |
259 | + def register_sprint(self): |
260 | + text = 'Register a meeting' |
261 | + summary = 'Register a developer sprint, summit, or gathering' |
262 | + return Link('/sprints/+new', text, summary=summary, icon='add') |
263 | + |
264 | |
265 | class HasSpecificationsView(LaunchpadView): |
266 | """Base class for several context-specific views that involve lists of |
267 | @@ -117,9 +124,8 @@ |
268 | is_sprint = False |
269 | has_drivers = False |
270 | |
271 | - # XXX: jsk: 2007-07-12: This method might be improved by |
272 | + # XXX: jsk: 2007-07-12 bug=173972: This method might be improved by |
273 | # replacing the conditional execution with polymorphism. |
274 | - # See https://bugs.launchpad.net/blueprint/+bug/173972. |
275 | def initialize(self): |
276 | if IPerson.providedBy(self.context): |
277 | self.is_person = True |
278 | @@ -145,7 +151,7 @@ |
279 | self.is_sprint = True |
280 | self.show_target = True |
281 | else: |
282 | - raise AssertionError, 'Unknown blueprint listing site' |
283 | + raise AssertionError('Unknown blueprint listing site.') |
284 | |
285 | if IHasDrivers.providedBy(self.context): |
286 | self.has_drivers = True |
287 | @@ -162,6 +168,8 @@ |
288 | else: |
289 | return _('Blueprints for $name', mapping=mapping) |
290 | |
291 | + page_title = 'Blueprints' |
292 | + |
293 | def mdzCsv(self): |
294 | """Quick hack for mdz, to get csv dump of specs.""" |
295 | import csv |
296 | @@ -382,7 +390,9 @@ |
297 | class RegisterABlueprintButtonView: |
298 | """View that renders a button to register a blueprint on its context.""" |
299 | |
300 | - def __call__(self): |
301 | + @cachedproperty |
302 | + def target_url(self): |
303 | + """The +addspec URL for the specifiation target or None""" |
304 | # Check if the context has an +addspec view available. |
305 | if queryMultiAdapter( |
306 | (self.context, self.request), name='+addspec'): |
307 | @@ -390,15 +400,25 @@ |
308 | else: |
309 | # otherwise find an adapter to ISpecificationTarget which will. |
310 | target = ISpecificationTarget(self.context) |
311 | + if target is None: |
312 | + return None |
313 | + else: |
314 | + return canonical_url( |
315 | + target, rootsite='blueprints', view_name='+addspec') |
316 | |
317 | + def __call__(self): |
318 | + if self.target_url is None: |
319 | + return '' |
320 | return """ |
321 | - <a href="%s/+addspec" id="addspec"> |
322 | - <img |
323 | - alt="Register a blueprint" |
324 | - src="/+icing/but-sml-registerablueprint.gif" |
325 | - /> |
326 | - </a> |
327 | - """ % canonical_url(target, rootsite='blueprints') |
328 | + <div id="involvement" class="portlet involvement"> |
329 | + <ul> |
330 | + <li style="border: none"> |
331 | + <a class="menu-link-register_blueprint sprite blueprints" |
332 | + href="%s">Register a blueprint</a> |
333 | + </li> |
334 | + </ul> |
335 | + </div> |
336 | + """ % self.target_url |
337 | |
338 | |
339 | class BlueprintsVHostBreadcrumb(Breadcrumb): |
340 | |
341 | === modified file 'lib/lp/blueprints/browser/sprint.py' |
342 | --- lib/lp/blueprints/browser/sprint.py 2009-10-30 16:38:20 +0000 |
343 | +++ lib/lp/blueprints/browser/sprint.py 2009-11-14 04:37:12 +0000 |
344 | @@ -149,6 +149,10 @@ |
345 | # a second h1 to display. But as this view implements IMajorHeadingView |
346 | # it should not include an h1 below the app buttons. |
347 | label = None |
348 | + |
349 | + @property |
350 | + def page_title(self): |
351 | + return '%s (sprint or meeting)' % self.context.title |
352 | |
353 | def initialize(self): |
354 | self.notices = [] |
355 | @@ -340,6 +344,8 @@ |
356 | return smartquote( |
357 | 'Review discussion topics for "%s" sprint' % self.context.title) |
358 | |
359 | + page_title = label |
360 | + |
361 | def initialize(self): |
362 | self.status_message = None |
363 | self.process_form() |
364 | @@ -470,15 +476,22 @@ |
365 | class SprintSetNavigationMenu(RegistryCollectionActionMenuBase): |
366 | """Action menu for sprints index.""" |
367 | usedfor = ISprintSet |
368 | - links = [ |
369 | + links = ( |
370 | 'register_team', |
371 | 'register_project', |
372 | + 'register_sprint', |
373 | 'create_account', |
374 | 'view_all_sprints', |
375 | - ] |
376 | + ) |
377 | + |
378 | + @enabled_with_permission('launchpad.View') |
379 | + def register_sprint(self): |
380 | + text = 'Register a meeting' |
381 | + summary = 'Register a developer sprint, summit, or gathering' |
382 | + return Link('+new', text, summary=summary, icon='add') |
383 | |
384 | def view_all_sprints(self): |
385 | - text = 'Show all sprints' |
386 | + text = 'Show all meetings' |
387 | return Link('+all', text, icon='list') |
388 | |
389 | |
390 | |
391 | === added file 'lib/lp/blueprints/browser/tests/test_menus.py' |
392 | --- lib/lp/blueprints/browser/tests/test_menus.py 1970-01-01 00:00:00 +0000 |
393 | +++ lib/lp/blueprints/browser/tests/test_menus.py 2009-11-14 04:37:13 +0000 |
394 | @@ -0,0 +1,40 @@ |
395 | +# Copyright 2009 Canonical Ltd. This software is licensed under the |
396 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
397 | + |
398 | +__metaclass__ = type |
399 | + |
400 | +import unittest |
401 | + |
402 | +from canonical.testing.layers import DatabaseFunctionalLayer |
403 | + |
404 | +from lp.blueprints.browser.specification import ( |
405 | + SpecificationActionMenu, SpecificationContextMenu) |
406 | +from lp.testing import TestCaseWithFactory |
407 | +from lp.testing.menu import check_menu_links |
408 | + |
409 | + |
410 | +class TestSpecificationMenus(TestCaseWithFactory): |
411 | + """Test specification menus links.""" |
412 | + layer = DatabaseFunctionalLayer |
413 | + |
414 | + def setUp(self): |
415 | + TestCaseWithFactory.setUp(self) |
416 | + self.specification = self.factory.makeSpecification() |
417 | + |
418 | + def test_SpecificationContextMenu(self): |
419 | + menu = SpecificationContextMenu(self.specification) |
420 | + self.assertTrue(check_menu_links(menu)) |
421 | + |
422 | + def test_SpecificationActionMenu(self): |
423 | + menu = SpecificationActionMenu(self.specification) |
424 | + self.assertTrue(check_menu_links(menu)) |
425 | + |
426 | + |
427 | +def test_suite(): |
428 | + suite = unittest.TestSuite() |
429 | + suite.addTest(unittest.TestLoader().loadTestsFromName(__name__)) |
430 | + return suite |
431 | + |
432 | + |
433 | +if __name__ == '__main__': |
434 | + unittest.TextTestRunner().run(test_suite()) |
435 | |
436 | === added file 'lib/lp/blueprints/browser/tests/test_specificationtarget.py' |
437 | --- lib/lp/blueprints/browser/tests/test_specificationtarget.py 1970-01-01 00:00:00 +0000 |
438 | +++ lib/lp/blueprints/browser/tests/test_specificationtarget.py 2009-11-14 04:37:13 +0000 |
439 | @@ -0,0 +1,93 @@ |
440 | +# Copyright 2009 Canonical Ltd. This software is licensed under the |
441 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
442 | + |
443 | +__metaclass__ = type |
444 | + |
445 | +import unittest |
446 | + |
447 | +from canonical.launchpad.layers import BlueprintLayer |
448 | +from canonical.testing.layers import DatabaseFunctionalLayer |
449 | + |
450 | +from lp.blueprints.interfaces.specificationtarget import ( |
451 | + IHasSpecifications, ISpecificationTarget) |
452 | +from lp.testing import login_person, TestCaseWithFactory |
453 | +from lp.testing.views import create_view |
454 | + |
455 | + |
456 | +class TestRegisterABlueprintButtonView(TestCaseWithFactory): |
457 | + """Test specification menus links.""" |
458 | + layer = DatabaseFunctionalLayer |
459 | + |
460 | + def verify_view(self, context, name): |
461 | + view = create_view( |
462 | + context, '+register-a-blueprint-button') |
463 | + self.assertEqual( |
464 | + 'http://blueprints.launchpad.dev/%s/+addspec' % name, |
465 | + view.target_url) |
466 | + self.assertTrue( |
467 | + '<div id="involvement" class="portlet involvement">' in view()) |
468 | + |
469 | + def test_specificationtarget(self): |
470 | + context = self.factory.makeProduct(name='almond') |
471 | + self.assertTrue(ISpecificationTarget.providedBy(context)) |
472 | + self.verify_view(context, context.name) |
473 | + |
474 | + def test_adaptable_to_specificationtarget(self): |
475 | + context = self.factory.makeProject(name='hazelnut') |
476 | + self.assertFalse(ISpecificationTarget.providedBy(context)) |
477 | + self.verify_view(context, context.name) |
478 | + |
479 | + def test_sprint(self): |
480 | + # Sprints are a special case. They are not ISpecificationTargets, |
481 | + # nor can they be adapted to a ISpecificationTarget, |
482 | + # but can create a spcification for a ISpecificationTarget. |
483 | + context = self.factory.makeSprint(title='Walnut', name='walnut') |
484 | + self.assertFalse(ISpecificationTarget.providedBy(context)) |
485 | + self.verify_view(context, 'sprints/%s' % context.name) |
486 | + |
487 | + |
488 | +class TestHasSpecificationsView(TestCaseWithFactory): |
489 | + """Test specification menus links.""" |
490 | + layer = DatabaseFunctionalLayer |
491 | + |
492 | + def setUp(self): |
493 | + TestCaseWithFactory.setUp(self) |
494 | + self.user = self.factory.makePerson(name="macadamia") |
495 | + login_person(self.user) |
496 | + |
497 | + def verify_involvment(self, context): |
498 | + self.assertTrue(IHasSpecifications.providedBy(context)) |
499 | + view = create_view( |
500 | + context, '+specs', layer=BlueprintLayer, principal=self.user) |
501 | + self.assertTrue( |
502 | + '<div id="involvement" class="portlet involvement">' in view()) |
503 | + |
504 | + def test_specificationtarget(self): |
505 | + context = self.factory.makeProduct(name='almond') |
506 | + self.verify_involvment(context) |
507 | + |
508 | + def test_adaptable_to_specificationtarget(self): |
509 | + context = self.factory.makeProject(name='hazelnut') |
510 | + self.verify_involvment(context) |
511 | + |
512 | + def test_sprint(self): |
513 | + context = self.factory.makeSprint(title='Walnut', name='walnut') |
514 | + self.verify_involvment(context) |
515 | + |
516 | + def test_person(self): |
517 | + context = self.factory.makePerson(name='pistachio') |
518 | + self.assertTrue(IHasSpecifications.providedBy(context)) |
519 | + view = create_view( |
520 | + context, '+specs', layer=BlueprintLayer, principal=self.user) |
521 | + self.assertFalse( |
522 | + '<div id="involvement" class="portlet involvement">' in view()) |
523 | + |
524 | + |
525 | +def test_suite(): |
526 | + suite = unittest.TestSuite() |
527 | + suite.addTest(unittest.TestLoader().loadTestsFromName(__name__)) |
528 | + return suite |
529 | + |
530 | + |
531 | +if __name__ == '__main__': |
532 | + unittest.TextTestRunner().run(test_suite()) |
533 | |
534 | === modified file 'lib/lp/blueprints/stories/blueprints/01-creation.txt' |
535 | --- lib/lp/blueprints/stories/blueprints/01-creation.txt 2009-09-22 15:02:41 +0000 |
536 | +++ lib/lp/blueprints/stories/blueprints/01-creation.txt 2009-11-14 04:37:12 +0000 |
537 | @@ -52,11 +52,12 @@ |
538 | |
539 | >>> user_browser.open('http://blueprints.launchpad.dev/ubuntu') |
540 | |
541 | -Users can press the graphical "Register a blueprint" button: |
542 | +Users can use the ISpecificationTarget involvement menu to register a |
543 | +blueprint. |
544 | |
545 | - >>> print find_tag_by_id(user_browser.contents, 'addspec') |
546 | - <a href="http://blueprints.launchpad.dev/ubuntu/+addspec" |
547 | - id="addspec"> <img alt="Register a blueprint"... |
548 | + >>> print extract_text( |
549 | + ... find_tag_by_id(user_browser.contents, 'involvement').a) |
550 | + Register a blueprint |
551 | |
552 | Users can also follow the textual "Register a blueprint" link: |
553 | |
554 | @@ -73,12 +74,6 @@ |
555 | |
556 | >>> user_browser.open('http://blueprints.launchpad.dev/ubuntu/hoary') |
557 | |
558 | -Users can press the graphical "Register a blueprint" button: |
559 | - |
560 | - >>> print find_tag_by_id(user_browser.contents, 'addspec') |
561 | - <a href="http://blueprints.launchpad.dev/ubuntu/hoary/+addspec" |
562 | - id="addspec"> <img alt="Register a blueprint"... |
563 | - |
564 | Users can also follow the textual "Register a blueprint" link: |
565 | |
566 | >>> for tag in find_tags_by_class( |
567 | @@ -94,11 +89,6 @@ |
568 | |
569 | >>> user_browser.open('http://blueprints.launchpad.dev/bzr') |
570 | |
571 | -Users can press the graphical "Register a blueprint" button: |
572 | - |
573 | - >>> print find_tag_by_id(user_browser.contents, 'addspec') |
574 | - <a href="http://blueprints.launchpad.dev/bzr/+addspec" |
575 | - id="addspec"> <img alt="Register a blueprint"... |
576 | |
577 | Users can also follow the textual "Register a blueprint" link: |
578 | |
579 | @@ -125,11 +115,6 @@ |
580 | |
581 | >>> user_browser.open('http://blueprints.launchpad.dev/firefox/1.0') |
582 | |
583 | -Users can press the graphical "Register a blueprint" button: |
584 | - |
585 | - >>> print find_tag_by_id(user_browser.contents, 'addspec') |
586 | - <a href="http://blueprints.launchpad.dev/firefox/1.0/+addspec" |
587 | - id="addspec"> <img alt="Register a blueprint" ... |
588 | |
589 | Users can also follow the textual "Register a blueprint" link: |
590 | |
591 | @@ -146,12 +131,6 @@ |
592 | |
593 | >>> user_browser.open('http://blueprints.launchpad.dev/mozilla') |
594 | |
595 | -Users can press the graphical "Register a blueprint" button: |
596 | - |
597 | - >>> print find_tag_by_id(user_browser.contents, 'addspec') |
598 | - <a href="http://blueprints.launchpad.dev/mozilla/+addspec" |
599 | - id="addspec"> <img alt="Register a blueprint" ... |
600 | - |
601 | Users can follow the textual "Register a blueprint" link: |
602 | |
603 | >>> for tag in find_tags_by_class( |
604 | @@ -167,12 +146,6 @@ |
605 | |
606 | >>> user_browser.open('http://blueprints.launchpad.dev/sprints/futurista') |
607 | |
608 | -Users can press the graphical "Register a blueprint" button: |
609 | - |
610 | - >>> print find_tag_by_id(user_browser.contents, 'addspec') |
611 | - <a href="http://blueprints.launchpad.dev/sprints/futurista/+addspec" |
612 | - id="addspec"> <img alt="Register a blueprint"... |
613 | - |
614 | Users can also follow the textual "Register a blueprint" link: |
615 | |
616 | >>> for tag in find_tags_by_class( |
617 | |
618 | === modified file 'lib/lp/blueprints/stories/blueprints/02-buglinks.txt' |
619 | --- lib/lp/blueprints/stories/blueprints/02-buglinks.txt 2009-09-18 23:33:06 +0000 |
620 | +++ lib/lp/blueprints/stories/blueprints/02-buglinks.txt 2009-11-14 04:37:12 +0000 |
621 | @@ -13,7 +13,7 @@ |
622 | ... 'http://launchpad.dev/firefox/+spec/svg-support') |
623 | >>> print extract_text(find_tag_by_id(anon_browser.contents, 'bug_links')) |
624 | Related bugs |
625 | - Bug #1: Firefox does not support SVG ... |
626 | + Bug #1: Firefox does not support SVG |
627 | |
628 | |
629 | == Adding Links == |
630 | |
631 | === modified file 'lib/lp/blueprints/stories/sprints/05-sprint-creation.txt' |
632 | --- lib/lp/blueprints/stories/sprints/05-sprint-creation.txt 2009-09-24 14:12:38 +0000 |
633 | +++ lib/lp/blueprints/stories/sprints/05-sprint-creation.txt 2009-11-14 04:37:12 +0000 |
634 | @@ -3,7 +3,8 @@ |
635 | We should also be able to create a new sprint. We do this off the Sprints |
636 | +new page. |
637 | |
638 | - >>> user_browser.open('http://launchpad.dev/sprints/+new') |
639 | + >>> user_browser.open('http://launchpad.dev/sprints') |
640 | + >>> user_browser.getLink('Register a meeting').click() |
641 | |
642 | >>> print user_browser.title |
643 | Register a meeting... |
644 | |
645 | === modified file 'lib/lp/blueprints/stories/standalone/subscribing.txt' |
646 | --- lib/lp/blueprints/stories/standalone/subscribing.txt 2009-09-22 20:21:30 +0000 |
647 | +++ lib/lp/blueprints/stories/standalone/subscribing.txt 2009-11-14 04:37:12 +0000 |
648 | @@ -49,7 +49,7 @@ |
649 | subscribed. |
650 | |
651 | >>> browser.getControl('Subscribe').click() |
652 | - >>> 'You have subscribed to this spec' in browser.contents |
653 | + >>> 'You have subscribed to this blueprint' in browser.contents |
654 | True |
655 | >>> 'subscriber-essential' in browser.contents |
656 | True |
657 | @@ -101,7 +101,7 @@ |
658 | >>> unsubit.value |
659 | 'Unsubscribe' |
660 | >>> unsubit.click() |
661 | - >>> 'You have unsubscribed from this spec.' in browser.contents |
662 | + >>> 'You have unsubscribed from this blueprint.' in browser.contents |
663 | True |
664 | >>> 'subscriber-inessential' in browser.contents |
665 | False |
666 | |
667 | === modified file 'lib/lp/blueprints/templates/hasspecifications-specs.pt' |
668 | --- lib/lp/blueprints/templates/hasspecifications-specs.pt 2009-09-22 15:02:41 +0000 |
669 | +++ lib/lp/blueprints/templates/hasspecifications-specs.pt 2009-11-14 04:37:12 +0000 |
670 | @@ -10,6 +10,8 @@ |
671 | <body> |
672 | |
673 | <tal:side metal:fill-slot="side"> |
674 | + <tal:register-blueprint |
675 | + content="structure context/@@+register-a-blueprint-button|nothing" /> |
676 | <tal:menu replace="structure context/@@+global-actions" /> |
677 | <div tal:replace="structure context/@@+portlet-latestspecs" /> |
678 | </tal:side> |
679 | @@ -31,9 +33,6 @@ |
680 | </tal:block> |
681 | </tal:block> |
682 | |
683 | - <div style="float: right;" |
684 | - tal:content="structure context/@@+register-a-blueprint-button|nothing" /> |
685 | - |
686 | <tal:no_specs condition="not: has_any_specs"> |
687 | <p> |
688 | Launchpad lets projects track the features they intend to implement over |
689 | @@ -107,14 +106,11 @@ |
690 | In this case, the drivers are: |
691 | </p> |
692 | |
693 | - <blockquote> |
694 | - <ul> |
695 | - <li tal:repeat="driver context/drivers" class="person"> |
696 | - <a tal:attributes="href driver/fmt:url" |
697 | - tal:content="driver/displayname">Foo Bar</a> |
698 | - </li> |
699 | - </ul> |
700 | - </blockquote> |
701 | + <ul class="subordinate"> |
702 | + <li tal:repeat="driver context/drivers"> |
703 | + <a tal:replace="structure driver/fmt:link">Foo Bar</a> |
704 | + </li> |
705 | + </ul> |
706 | </tal:not_driver> |
707 | <tal:is_driver condition="context/required:launchpad.Driver"> |
708 | Since you are a driver of |
709 | @@ -130,14 +126,13 @@ |
710 | release management with Launchpad. |
711 | </p> |
712 | |
713 | - <blockquote> |
714 | - <ul class="menu"> |
715 | - <li class="info"> |
716 | - <a href="https://help.launchpad.net/BlueprintDocumentation" |
717 | - >Read more about tracking blueprints</a> |
718 | - </li> |
719 | - </ul> |
720 | - </blockquote> |
721 | + <ul class="horizontal"> |
722 | + <li> |
723 | + <a class="info sprite" |
724 | + href="https://help.launchpad.net/BlueprintDocumentation">Read |
725 | + more about tracking blueprints</a> |
726 | + </li> |
727 | + </ul> |
728 | |
729 | </tal:no_specs> |
730 | <tal:has_specs condition="has_any_specs"> |
731 | |
732 | === modified file 'lib/lp/blueprints/templates/specification-index.pt' |
733 | --- lib/lp/blueprints/templates/specification-index.pt 2009-09-23 08:20:02 +0000 |
734 | +++ lib/lp/blueprints/templates/specification-index.pt 2009-11-14 04:37:12 +0000 |
735 | @@ -347,19 +347,7 @@ |
736 | </div> |
737 | |
738 | <tal:side metal:fill-slot="side"> |
739 | - <div class="portlet"> |
740 | - <ul> |
741 | - <li tal:condition="context/menu:context/edit/enabled"> |
742 | - <a tal:replace="structure context/menu:context/edit/fmt:link" /> |
743 | - </li> |
744 | - <li tal:condition="context/menu:context/supersede/enabled"> |
745 | - <a tal:replace="structure context/menu:context/supersede/fmt:link" /> |
746 | - </li> |
747 | - <li tal:condition="context/menu:context/retarget/enabled"> |
748 | - <a tal:replace="structure context/menu:context/retarget/fmt:link" /> |
749 | - </li> |
750 | - </ul> |
751 | - </div> |
752 | + <tal:menu replace="structure context/@@+global-actions" /> |
753 | |
754 | <div tal:replace="structure context/@@+portlet-subscribers" /> |
755 | </tal:side> |
756 | |
757 | === modified file 'lib/lp/blueprints/templates/specificationtarget-documentation.pt' |
758 | --- lib/lp/blueprints/templates/specificationtarget-documentation.pt 2009-09-17 21:20:14 +0000 |
759 | +++ lib/lp/blueprints/templates/specificationtarget-documentation.pt 2009-11-14 04:37:13 +0000 |
760 | @@ -10,10 +10,9 @@ |
761 | <body> |
762 | <metal:main fill-slot="main" tal:define="specs view/documentation"> |
763 | <p> |
764 | - To classify a blueprint as documentation, check the |
765 | - “Is Informational” box on its “Edit Details” |
766 | - page. When the blueprint is marked "Approved" then it will show |
767 | - up in this listing. |
768 | + To classify a blueprint as documentation, set the Implementation status |
769 | + to “Informational” When the blueprint's Definition status is |
770 | + marked “Approved”, it will appear in this listing. |
771 | </p> |
772 | |
773 | <table id="documentation-listing-table"> |
774 | |
775 | === modified file 'lib/lp/blueprints/templates/sprint-portlet-attendees.pt' |
776 | --- lib/lp/blueprints/templates/sprint-portlet-attendees.pt 2009-09-23 13:49:22 +0000 |
777 | +++ lib/lp/blueprints/templates/sprint-portlet-attendees.pt 2009-11-14 04:37:13 +0000 |
778 | @@ -11,7 +11,7 @@ |
779 | <div class="portletBody portletContent"> |
780 | |
781 | <ul> |
782 | - <li class="person" tal:repeat="attendance context/attendances"> |
783 | + <li tal:repeat="attendance context/attendances"> |
784 | <a tal:replace="structure attendance/attendee/fmt:link">Foo Bar</a><br /> |
785 | <div class="discreet"> |
786 | <span tal:replace="python:view.formatDate(attendance.time_starts)"> |
787 | |
788 | === modified file 'lib/lp/blueprints/templates/sprint-register.pt' |
789 | --- lib/lp/blueprints/templates/sprint-register.pt 2009-09-18 17:44:08 +0000 |
790 | +++ lib/lp/blueprints/templates/sprint-register.pt 2009-11-14 04:37:12 +0000 |
791 | @@ -8,6 +8,10 @@ |
792 | > |
793 | |
794 | <body> |
795 | + <metal:block fill-slot="head_epilogue"> |
796 | + <metal:yui-dependencies |
797 | + use-macro="context/@@launchpad_widget_macros/yui2calendar-dependencies" /> |
798 | + </metal:block> |
799 | |
800 | <div metal:fill-slot="main"> |
801 | <div metal:use-macro="context/@@launchpad_form/form"> |
802 | |
803 | === modified file 'lib/lp/bugs/browser/buglinktarget.py' |
804 | --- lib/lp/bugs/browser/buglinktarget.py 2009-08-13 17:04:41 +0000 |
805 | +++ lib/lp/bugs/browser/buglinktarget.py 2009-11-14 04:37:12 +0000 |
806 | @@ -30,19 +30,15 @@ |
807 | class BugLinkView(LaunchpadFormView): |
808 | """This view is used to link bugs to any IBugLinkTarget.""" |
809 | |
810 | - label = _('Link to bug report') |
811 | - |
812 | + label = _('Link a bug report') |
813 | schema = IBugLinkForm |
814 | |
815 | focused_element_id = 'bug' |
816 | |
817 | @property |
818 | - def page_title(self): |
819 | - return 'Link question #%s to a bug report' % self.context.id |
820 | - |
821 | - @property |
822 | - def label(self): |
823 | - return 'Link question to a bug report' |
824 | + def cancel_url(self): |
825 | + """See `LaunchpadFormview`.""" |
826 | + return canonical_url(self.context) |
827 | |
828 | @action(_('Link')) |
829 | def linkBug(self, action, data): |
830 | @@ -98,17 +94,13 @@ |
831 | """This view is used to remove bug links from any IBugLinkTarget.""" |
832 | |
833 | label = _('Remove links to bug reports') |
834 | - |
835 | schema = IUnlinkBugsForm |
836 | custom_widget('bugs', LabeledMultiCheckBoxWidget) |
837 | |
838 | @property |
839 | - def page_title(self): |
840 | - return 'Remove bug links from question #%s' % self.context.id |
841 | - |
842 | - @property |
843 | - def label(self): |
844 | - return 'Remove links to bug reports' |
845 | + def cancel_url(self): |
846 | + """See `LaunchpadFormview`.""" |
847 | + return canonical_url(self.context) |
848 | |
849 | @action(_('Remove')) |
850 | def unlinkBugs(self, action, data): |
851 | @@ -134,4 +126,3 @@ |
852 | """ |
853 | return [bug for bug in self.context.bugs |
854 | if check_permission('launchpad.View', bug)] |
855 | - |
856 | |
857 | === modified file 'lib/lp/bugs/browser/tests/buglinktarget-views.txt' |
858 | --- lib/lp/bugs/browser/tests/buglinktarget-views.txt 2009-06-12 16:36:02 +0000 |
859 | +++ lib/lp/bugs/browser/tests/buglinktarget-views.txt 2009-11-14 04:37:13 +0000 |
860 | @@ -24,8 +24,16 @@ |
861 | |
862 | == Link Bug View == |
863 | |
864 | -The +linkbug view is used to link bugs to IBugLinkTarget. It has a |
865 | -simple widget to enter the bug number or nickname of the bug to link |
866 | +The +linkbug view is used to link bugs to IBugLinkTarget. |
867 | + |
868 | + >>> view = create_view(cve, name='+linkbug') |
869 | + >>> print view.label |
870 | + Link a bug report |
871 | + |
872 | + >>> print view.cancel_url |
873 | + http://launchpad.dev/bugs/cve/2005-2730 |
874 | + |
875 | +It has a simple widget to enter the bug number or nickname of the bug to link |
876 | to. After it links the bug, it sends a ObjectModifiedEvent. |
877 | |
878 | >>> request = LaunchpadTestRequest( |
879 | @@ -70,8 +78,16 @@ |
880 | |
881 | |
882 | The +unlinkbug view is used to unlink a selection of bugs from an |
883 | -IBugLinkTarget. After removing the bugs, it sends a SQLObjectModified |
884 | -event. |
885 | +IBugLinkTarget. |
886 | + |
887 | + >>> view = create_view(cve, name='+unlinkbug') |
888 | + >>> print view.label |
889 | + Remove links to bug reports |
890 | + |
891 | + >>> print view.cancel_url |
892 | + http://launchpad.dev/bugs/cve/2005-2730 |
893 | + |
894 | +After removing the bugs, it sends a SQLObjectModified event. |
895 | |
896 | >>> request = LaunchpadTestRequest( |
897 | ... method="POST", |
898 | |
899 | === modified file 'lib/lp/coop/answersbugs/stories/question-buglink.txt' |
900 | --- lib/lp/coop/answersbugs/stories/question-buglink.txt 2009-09-18 15:24:30 +0000 |
901 | +++ lib/lp/coop/answersbugs/stories/question-buglink.txt 2009-11-14 04:37:12 +0000 |
902 | @@ -70,7 +70,7 @@ |
903 | |
904 | >>> user_browser.getLink('Remove bug link').click() |
905 | >>> print user_browser.title |
906 | - Remove bug links from question #2... |
907 | + Remove links to bug reports : Question #... |
908 | |
909 | The list of linked bugs is displayed. The user selects the link to |
910 | remove and clicks the 'Remove' button. |
911 | |
912 | === modified file 'lib/lp/registry/browser/distribution.py' |
913 | --- lib/lp/registry/browser/distribution.py 2009-11-10 11:31:06 +0000 |
914 | +++ lib/lp/registry/browser/distribution.py 2009-11-14 04:37:13 +0000 |
915 | @@ -452,7 +452,7 @@ |
916 | HasSpecificationsMenuMixin): |
917 | usedfor = IDistribution |
918 | facet = 'specifications' |
919 | - links = ['listall', 'doc', 'assignments', 'new'] |
920 | + links = ['listall', 'doc', 'assignments', 'new', 'register_sprint'] |
921 | |
922 | |
923 | class DistributionPackageSearchView(PackageSearchViewBase): |
924 | |
925 | === modified file 'lib/lp/registry/browser/distroseries.py' |
926 | --- lib/lp/registry/browser/distroseries.py 2009-11-07 01:45:32 +0000 |
927 | +++ lib/lp/registry/browser/distroseries.py 2009-11-14 04:37:13 +0000 |
928 | @@ -227,7 +227,9 @@ |
929 | |
930 | usedfor = IDistroSeries |
931 | facet = 'specifications' |
932 | - links = ['listall', 'listdeclined', 'assignments', 'setgoals', 'new'] |
933 | + links = [ |
934 | + 'listall', 'listdeclined', 'assignments', 'setgoals', |
935 | + 'new', 'register_sprint'] |
936 | |
937 | |
938 | class DistroSeriesPackageSearchView(PackageSearchViewBase): |
939 | |
940 | === modified file 'lib/lp/registry/browser/person.py' |
941 | --- lib/lp/registry/browser/person.py 2009-10-30 14:55:25 +0000 |
942 | +++ lib/lp/registry/browser/person.py 2009-11-14 04:37:13 +0000 |
943 | @@ -1808,6 +1808,7 @@ |
944 | class PersonSpecFeedbackView(HasSpecificationsView): |
945 | |
946 | label = 'Feature feedback requests' |
947 | + page_title = label |
948 | |
949 | @cachedproperty |
950 | def feedback_specs(self): |
951 | |
952 | === modified file 'lib/lp/registry/browser/product.py' |
953 | --- lib/lp/registry/browser/product.py 2009-11-07 00:49:26 +0000 |
954 | +++ lib/lp/registry/browser/product.py 2009-11-14 04:37:12 +0000 |
955 | @@ -468,7 +468,7 @@ |
956 | HasSpecificationsMenuMixin): |
957 | usedfor = IProduct |
958 | facet = 'specifications' |
959 | - links = ['listall', 'doc', 'assignments', 'new'] |
960 | + links = ['listall', 'doc', 'assignments', 'new', 'register_sprint'] |
961 | |
962 | |
963 | def _sort_distros(a, b): |
964 | |
965 | === modified file 'lib/lp/registry/browser/productseries.py' |
966 | --- lib/lp/registry/browser/productseries.py 2009-11-11 00:19:14 +0000 |
967 | +++ lib/lp/registry/browser/productseries.py 2009-11-14 04:37:13 +0000 |
968 | @@ -256,7 +256,9 @@ |
969 | |
970 | usedfor = IProductSeries |
971 | facet = 'specifications' |
972 | - links = ['listall', 'assignments', 'setgoals', 'listdeclined', 'new'] |
973 | + links = [ |
974 | + 'listall', 'assignments', 'setgoals', 'listdeclined', |
975 | + 'new', 'register_sprint'] |
976 | |
977 | |
978 | class ProductSeriesOverviewNavigationMenu(NavigationMenu): |
979 | |
980 | === modified file 'lib/lp/registry/browser/project.py' |
981 | --- lib/lp/registry/browser/project.py 2009-11-10 05:05:49 +0000 |
982 | +++ lib/lp/registry/browser/project.py 2009-11-14 04:37:13 +0000 |
983 | @@ -273,7 +273,7 @@ |
984 | HasSpecificationsMenuMixin): |
985 | usedfor = IProject |
986 | facet = 'specifications' |
987 | - links = ['listall', 'doc', 'assignments', 'new'] |
988 | + links = ['listall', 'doc', 'assignments', 'new', 'register_sprint'] |
989 | |
990 | |
991 | class ProjectAnswersMenu(QuestionCollectionAnswersMenu): |
992 | |
993 | === modified file 'lib/lp/registry/browser/tests/product-menus.txt' |
994 | --- lib/lp/registry/browser/tests/product-menus.txt 2009-10-08 18:15:31 +0000 |
995 | +++ lib/lp/registry/browser/tests/product-menus.txt 2009-11-14 04:37:12 +0000 |
996 | @@ -9,32 +9,12 @@ |
997 | The check_menu_links() function is defined here to make it simple to |
998 | test all the product menu classes below. |
999 | |
1000 | - >>> from zope.component import getMultiAdapter |
1001 | - >>> from canonical.lazr.testing.menus import make_fake_request |
1002 | - >>> from canonical.launchpad.webapp.publisher import canonical_url |
1003 | - >>> from lp.registry.interfaces.product import IProductSet |
1004 | - |
1005 | - >>> def check_menu_links(menu): |
1006 | - ... context = menu.context |
1007 | - ... is_sane_menu = True |
1008 | - ... for link in menu.iterlinks(): |
1009 | - ... if '?' in link.target: |
1010 | - ... view_name, _args = link.target.split('?') |
1011 | - ... else: |
1012 | - ... view_name = link.target |
1013 | - ... url = canonical_url(context, view_name=view_name) |
1014 | - ... request = make_fake_request(url) |
1015 | - ... try: |
1016 | - ... view = getMultiAdapter((context, request), name=view_name) |
1017 | - ... except: |
1018 | - ... is_sane_menu = False |
1019 | - ... print 'Bad link %s: %s' % (link.name, url) |
1020 | - ... print is_sane_menu |
1021 | - |
1022 | + >>> from lp.testing.menu import check_menu_links |
1023 | >>> from lp.registry.browser.product import ( |
1024 | ... ProductBugsMenu, ProductNavigationMenu, |
1025 | ... ProductOverviewMenu, ProductSpecificationsMenu) |
1026 | - >>> product = getUtility(IProductSet)['firefox'] |
1027 | + |
1028 | + >>> product = factory.makeProduct() |
1029 | |
1030 | >>> check_menu_links(ProductOverviewMenu(product)) |
1031 | True |
1032 | |
1033 | === modified file 'lib/lp/testing/factory.py' |
1034 | --- lib/lp/testing/factory.py 2009-11-13 14:58:08 +0000 |
1035 | +++ lib/lp/testing/factory.py 2009-11-14 04:37:12 +0000 |
1036 | @@ -619,12 +619,13 @@ |
1037 | description=description, |
1038 | owner=owner) |
1039 | |
1040 | - def makeSprint(self, title=None): |
1041 | + def makeSprint(self, title=None, name=None): |
1042 | """Make a sprint.""" |
1043 | if title is None: |
1044 | title = self.getUniqueString('title') |
1045 | owner = self.makePerson() |
1046 | - name = self.getUniqueString('name') |
1047 | + if name is None: |
1048 | + name = self.getUniqueString('name') |
1049 | time_starts = datetime(2009, 1, 1, tzinfo=pytz.UTC) |
1050 | time_ends = datetime(2009, 1, 2, tzinfo=pytz.UTC) |
1051 | time_zone = 'UTC' |
1052 | |
1053 | === modified file 'lib/lp/testing/menu.py' |
1054 | --- lib/lp/testing/menu.py 2009-11-13 13:06:50 +0000 |
1055 | +++ lib/lp/testing/menu.py 2009-11-14 04:37:13 +0000 |
1056 | @@ -14,6 +14,9 @@ |
1057 | def check_menu_links(menu): |
1058 | context = menu.context |
1059 | for link in menu.iterlinks(): |
1060 | + if link.target.startswith('/'): |
1061 | + # The context is not the context of this target. |
1062 | + continue |
1063 | if '?' in link.target: |
1064 | view_name, _args = link.target.split('?') |
1065 | else: |
This is my branch to fix 3.0 UI inconsistencies in blueprints.
lp:~sinzui/launchpad/blueprints-ui /bugs.launchpad .net/bugs/ 436249 /bugs.launchpad .net/bugs/ 456192 /bugs.launchpad .net/bugs/ 456974 /bugs.launchpad .net/bugs/ 422693 implementation: no one
Diff size: 753
Launchpad bug: https:/
https:/
https:/
https:/
Test command: ./bin/test -vv -m lp.blueprints -t buglinktarget-views
Pre-
Target release: 3.1.11
= Fix 3.0 UI inconsistencies in blueprints =
Bug 436249 [specification- index displays an empty global menu]
When I do not have permission to edit a blueprint the box still renders.
Bug 456192 [Page that links blueprint to bug report says "question" instead]
When I go to a blueprint page and from there click on to linking a bug
report. The heading and title for this page say "Link question to a bug
report" and "Link question #12345 to a bug report," respectively.
blueprint and questions share the same view for linking to bugs. The view
needs to be smarter by testing he context type, or the views can be
subclassed.
Bug 456974 [the 1.0 register a blueprint button is showing on a 3.0 page]
The page should use the involvement menu instead.
Bug 422693 [Register a sprint is missing from /sprints]
The sprints top-level collection page needs a link to register a sprint.
== Rules ==
Bug 436249 [specification- index displays an empty global menu]
* Replace the hard coded menu with a navigation menu.
Bug 456192 [Page that links blueprint to bug report says "question" instead]
* Simplify the page_title because the the view is used by many objects,
and the context object is already listed in the breadcrumbs and title.
Bug 456974 [the 1.0 register a blueprint button is showing on a 3.0 page]
* Add an involvement menu to the pages that use the old buttons.
Bug 422693 [Register a sprint is missing from /sprints]
* Add a Register meeting link to the menu.
== QA ==
Bug 436249 [specification- index displays an empty global menu]
* Visit a specification that you cannot edit.
* Verify that an empty global menu is not displayed.
Bug 456192 [Page that links blueprint to bug report says "question" instead]
* Choose the Link to bug link.
* Verify the heading does not not mention 'question'.
Bug 456974 [the 1.0 register a blueprint button is showing on a 3.0 page]
* Visit the front page for a project's blueprints.
* Verify that the 1.0 button is not shown.
* Verify that the page has an involvement menu to register a blueprint.
Bug 422693 [Register a sprint is missing from /sprints]
* Visit /sprints
* Verify there is a link to create a meeting.
== Lint ==
Linting changed files: /launchpad/ pagetitles. py blueprints/ browser/ configure. zcml blueprints/ browser/ specification. py blueprints/ browser/ specificationta rget.py blueprints/ browser/ sprint. py blueprints/ browser/ tests/test_ menus.py blueprints/ browser/ tests/test_ specificationta rget.py blueprints/ stories/ blueprints/ 01-creation. txt blueprints/ stories/ bl...
lib/canonical
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/