> Hi Edwin.
>
> This this was a nice feature to use on the sp page. I think we should consider
> using it on the dsp page: https://launchpad.dev/ubuntu/+source/evolution. We
> have a post back that some people have expressed concern about how easy it is
> to make a mistake. I would not say this is change we must do because the post
> back always returns the user to the dsp page--using the sp as the next_url
> would be confusing.
>
> I think we should remove the edit/remove links from the +packaging listing.
> There is not enough information on this page to make that decision.
This was supposed to be a simple change for the UI review. It has grown
quite large, so I can create a new merge proposal if you would like.
I started off trying to use +remove-packaging page for the
$distrosourcepackage/+packages page, but I saw that the replaced code
was also used by $product/+packages page, so I changed that page also.
After I got the +remove-packaging page to return to the previous page, I
discovered that the edit link on the $distrosourcepackage/+packages was
returning you to a different page.
All these changes broke a ton of tests.
Pages to check
--------------
The edit and remove buttons for each series are hidden now.
https://launchpad.dev/ubuntu/hoary/+packaging
The remove button now takes you to the $sourcepackage/+remove-packaging page,
and the edit button no
https://launchpad.dev/ubuntu/+source/evolution
The remove button now takes you to the $sourcepackage/+remove-packaging page.
https://launchpad.dev/evolution/+packages
This page shouldn't have changed, but if you want to check that the
show_edit_buttons annotation is passed correctly, you'll need to look at it.
https://launchpad.dev/ubuntu/hoary/+source/evolution
Implementation details
----------------------
Removed trailing white-space.
lib/canonical/launchpad/icing/style-3-0.css.in
Added Mixin to enable forms to return to their referring page.
lib/canonical/launchpad/templates/launchpad-form.pt
lib/canonical/launchpad/webapp/launchpadform.py
Use the ReturnToReferrerMixin that provides the cancel_url and next_url.
Hide the edit/remove buttons by default, but show them in the
annotations portlet, because its view sets
request.annotations['show_edit_buttons'].
sourcepackage-upstream-connections.pt now has it's own view, since
it can't share the view with annotations portlet or show_edit_buttons
would always be true.
lib/lp/registry/templates/sourcepackage-upstream-connections.pt
lib/lp/registry/browser/sourcepackage.py
lib/lp/registry/browser/tests/packaging-views.txt
lib/lp/registry/browser/configure.zcml
Removed PackagingDeleteView and related code.
lib/lp/registry/browser/distributionsourcepackage.py
lib/lp/registry/browser/packaging.py
lib/lp/registry/browser/product.py
lib/lp/registry/templates/distributionsourcepackage-index.pt
lib/lp/registry/templates/product-packages.pt
Added error message for when a user loads this page after the
upstream link has been deleted by someone else.
lib/lp/registry/templates/sourcepackage-remove-packaging.pt
Tests:
lib/lp/registry/browser/tests/sourcepackage-views.txt
lib/lp/registry/browser/tests/test_packaging.py
lib/lp/registry/stories/packaging/xx-distributionsourcepackage-packaging-concurrent-deletion.txt
lib/lp/registry/stories/packaging/xx-distributionsourcepackage-packaging.txt
lib/lp/registry/stories/packaging/xx-sourcepackage-packaging.txt
lib/lp/registry/stories/product/xx-product-package-pages.txt
lib/lp/registry/stories/productseries/xx-productseries-delete.txt
lib/lp/soyuz/stories/soyuz/xx-distroseries-sources.txt
Tests
-----
./bin/test -vvt '/packaging-views.txt|/sourcepackage-views.txt|/test_packaging.py|xx-distributionsourcepackage-packaging-concurrent-deletion.txt|xx-distributionsourcepackage-packaging.txt|xx-sourcepackage-packaging.txt|xx-product-package-pages.txt|xx-productseries-delete.txt|soyuz/xx-distroseries-sources.txt'
Incremental diff
----------------
=== modified file 'lib/canonical/launchpad/icing/style-3-0.css.in'
--- lib/canonical/launchpad/icing/style-3-0.css.in 2010-02-17 00:43:19 +0000
+++ lib/canonical/launchpad/icing/style-3-0.css.in 2010-03-02 00:49:19 +0000
@@ -814,7 +814,7 @@
}
input[type="submit"].icon-only {
vertical-align: middle;
- border: 0;
+ border: 0;
padding: 0;
height: 16px;
width: 16px;
=== modified file 'lib/canonical/launchpad/templates/launchpad-form.pt'
--- lib/canonical/launchpad/templates/launchpad-form.pt 2009-11-26 09:18:22 +0000
+++ lib/canonical/launchpad/templates/launchpad-form.pt 2010-03-02 04:07:05 +0000
@@ -16,6 +16,13 @@
accept-charset="UTF-8">
+
+ This field is used by the ReturnToReferrerMixin.
+
+
This is the description of the form.
=== modified file 'lib/canonical/launchpad/webapp/launchpadform.py'
--- lib/canonical/launchpad/webapp/launchpadform.py 2010-02-19 01:50:36 +0000
+++ lib/canonical/launchpad/webapp/launchpadform.py 2010-03-02 03:55:25 +0000
@@ -7,10 +7,11 @@
__metaclass__ = type
__all__ = [
- 'LaunchpadFormView',
- 'LaunchpadEditFormView',
'action',
'custom_widget',
+ 'LaunchpadEditFormView',
+ 'LaunchpadFormView',
+ 'ReturnToReferrerMixin',
'safe_action',
]
@@ -32,7 +33,7 @@
IMultiLineWidgetLayout, ICheckBoxWidgetLayout,
IAlwaysSubmittedWidget, UnsafeFormGetSubmissionError)
from canonical.launchpad.webapp.menu import escape
-from canonical.launchpad.webapp.publisher import LaunchpadView
+from canonical.launchpad.webapp.publisher import canonical_url, LaunchpadView
classImplements(CheckBoxWidget, ICheckBoxWidgetLayout)
@@ -434,3 +435,30 @@
"""
action.is_safe = True
return action
+
+
+class ReturnToReferrerMixin:
+ """Return to the previous page after submitting the form.
+
+ The _return_url is stored in a hidden field in the launchpad-form.pt
+ between the request to view the form and submitting the form.
+ """
+
+ @property
+ def _return_url(self):
+ """See `LaunchpadFormView`."""
+ # The referer header we want is only available before the view's
+ # form submits to itself. This field is a hidden input in the form.
+ referrer = self.request.form.get('_return_url')
+ if referrer is None:
+ # "referer" is misspelled in the HTTP specification.
+ referrer = self.request.getHeader('referer')
+
+ if (referrer is not None
+ and referrer.startswith(self.request.getApplicationURL())):
+ return referrer
+ else:
+ return canonical_url(self.context)
+
+ next_url = _return_url
+ cancel_url = _return_url
=== modified file 'lib/lp/registry/browser/configure.zcml'
--- lib/lp/registry/browser/configure.zcml 2010-02-26 22:59:30 +0000
+++ lib/lp/registry/browser/configure.zcml 2010-03-02 19:33:41 +0000
@@ -1958,7 +1958,7 @@
permission="zope.Public"
name="+upstream-connections"
facet="overview"
- class="lp.registry.browser.sourcepackage.SourcePackageAssociationPortletView"
+ class="lp.registry.browser.sourcepackage.SourcePackageUpstreamConnectionsView"
template="../templates/sourcepackage-upstream-connections.pt"/>
' % (
- vocabulary.getTerm(packaging).token)
-
- def renderDeletePackagingAction(self):
- """Render a submit input for the delete_packaging_action."""
- assert self.can_delete_packaging, 'User cannot delete Packaging.'
- return ('' % self.delete_packaging_action.__name__)
-
- def handleDeletePackagingError(self, action, data, errors):
- """Handle errors on package link deletion.
-
- If 'packaging' is not set in the form data, we assume that means the
- provided Packaging id was not found, which should only happen if the
- same Packaging object was concurrently deleted. In this case, we want
- to display a more informative error message than the default 'Invalid
- value'.
- """
- if data.get('packaging') is None:
- self.setFieldError(
- 'packaging',
- _("This upstream association was deleted already."))
-
- @action(_("Delete Link"), name='delete_packaging',
- failure=handleDeletePackagingError)
- def delete_packaging_action(self, action, data):
- """Delete a Packaging association."""
- packaging = data['packaging']
- productseries = packaging.productseries
- distroseries = packaging.distroseries
- getUtility(IPackagingUtil).deletePackaging(
- productseries, packaging.sourcepackagename, distroseries)
- self.request.response.addNotification(
- _("Removed upstream association between ${product} "
- "${productseries} and ${distroseries}.", mapping=dict(
- product=productseries.product.displayname,
- productseries=productseries.displayname,
- distroseries=distroseries.displayname)))
=== modified file 'lib/lp/registry/browser/product.py'
--- lib/lp/registry/browser/product.py 2010-02-16 21:21:14 +0000
+++ lib/lp/registry/browser/product.py 2010-03-03 18:46:05 +0000
@@ -81,7 +81,6 @@
from lp.registry.browser.distribution import UsesLaunchpadMixin
from lp.registry.browser.menu import (
IRegistryCollectionNavigationMenu, RegistryCollectionActionMenuBase)
-from lp.registry.browser.packaging import PackagingDeleteView
from lp.answers.browser.faqtarget import FAQTargetNavigationMixin
from canonical.launchpad.browser.feeds import FeedsMixin
from lp.registry.browser.productseries import get_series_branch_error
@@ -95,13 +94,15 @@
StructuralSubscriptionTargetTraversalMixin)
from canonical.launchpad.mail import format_address, simple_sendmail
from canonical.launchpad.webapp import (
- ApplicationMenu, LaunchpadEditFormView, LaunchpadFormView, LaunchpadView,
- Link, Navigation, StandardLaunchpadFacets, action, canonical_url,
- custom_widget, enabled_with_permission, sorted_version_numbers,
+ ApplicationMenu, canonical_url, enabled_with_permission, LaunchpadView,
+ Link, Navigation, sorted_version_numbers, StandardLaunchpadFacets,
stepthrough, stepto, structured)
from canonical.launchpad.webapp.authorization import check_permission
from canonical.launchpad.webapp.batching import BatchNavigator
from canonical.launchpad.webapp.breadcrumb import Breadcrumb
+from canonical.launchpad.webapp.launchpadform import (
+ action, custom_widget, LaunchpadEditFormView, LaunchpadFormView,
+ ReturnToReferrerMixin)
from canonical.launchpad.webapp.menu import NavigationMenu
from canonical.widgets.popup import PersonPickerWidget
from canonical.widgets.date import DateWidget
@@ -897,17 +898,11 @@
check_permission('launchpad.Commercial', self.context))
-class ProductPackagesView(PackagingDeleteView):
+class ProductPackagesView(LaunchpadView):
"""View for displaying product packaging"""
label = 'Linked packages'
-
- @property
- def all_packaging(self):
- """See `PackagingDeleteView`."""
- for series in self.context.series:
- for packaging in series.packagings:
- yield packaging
+ page_title = label
@cachedproperty
def series_packages(self):
@@ -921,23 +916,11 @@
field: '},
}]
"""
- # This method is a superset of all_packaging. While all_packaging will
- # be called several times as data is mutated, series_packages should
- # only be called during render().
packaged_series = []
for series in self.context.series:
packagings = []
for packaging in series.packagings:
- form_id = 'delete-%s-%s-%s' % (
- packaging.distroseries.name,
- packaging.sourcepackagename.name,
- packaging.productseries.name,
- )
- packaging_field = dict(
- packaging=packaging,
- form_id=form_id,
- field=self._renderHiddenPackagingField(packaging))
- packagings.append(packaging_field)
+ packagings.append(packaging)
packaged_series.append(dict(
series=series, packagings=packagings))
return packaged_series
@@ -1262,7 +1245,8 @@
return canonical_url(self.context)
-class ProductReviewLicenseView(ProductEditView, EditPrivateBugsMixin):
+class ProductReviewLicenseView(ReturnToReferrerMixin,
+ ProductEditView, EditPrivateBugsMixin):
"""A view to review a project and change project privileges."""
label = "Review project"
field_names = [
@@ -1302,27 +1286,6 @@
# supervisor.
self.validate_private_bugs(data)
- @property
- def next_url(self):
- """See `LaunchpadFormView`."""
- # The referer header we want is only available before the view's
- # form submits to itself. This field is a hidden input in the form.
- referrer = self.request.form.get('next_url')
- if referrer is None:
- referrer = self.request.getHeader('referer')
-
- if (referrer is not None
- and referrer.startswith(self.request.getApplicationURL())):
- return referrer
- else:
- return canonical_url(self.context)
-
- @property
- def cancel_url(self):
- """See `LaunchpadFormView`."""
- return self.next_url
-
-
class ProductAddSeriesView(LaunchpadFormView):
"""A form to add new product series"""
@@ -1613,7 +1576,7 @@
self.request.form['summary'] = data['summary']
-class ProjectAddStepTwo(StepView, ProductLicenseMixin):
+class ProjectAddStepTwo(StepView, ProductLicenseMixin, ReturnToReferrerMixin):
"""Step 2 (of 2) in the +new project add wizard."""
_field_names = ['displayname', 'name', 'title', 'summary',
=== modified file 'lib/lp/registry/browser/sourcepackage.py'
--- lib/lp/registry/browser/sourcepackage.py 2010-02-27 01:21:37 +0000
+++ lib/lp/registry/browser/sourcepackage.py 2010-03-02 22:55:22 +0000
@@ -13,6 +13,7 @@
'SourcePackageHelpView',
'SourcePackageNavigation',
'SourcePackageRemoveUpstreamView',
+ 'SourcePackageUpstreamConnectionsView',
'SourcePackageView',
]
@@ -49,12 +50,15 @@
from lp.translations.interfaces.potemplate import IPOTemplateSet
from canonical.launchpad import _
from canonical.launchpad.webapp import (
- action, ApplicationMenu, custom_widget, GetitemNavigation,
- LaunchpadFormView, Link, redirection, StandardLaunchpadFacets, stepto)
+ ApplicationMenu, GetitemNavigation, Link, redirection,
+ StandardLaunchpadFacets, stepto)
+from canonical.launchpad.webapp.launchpadform import (
+ action, custom_widget, LaunchpadFormView, ReturnToReferrerMixin)
from canonical.launchpad.webapp import canonical_url
from canonical.launchpad.webapp.authorization import check_permission
from canonical.launchpad.webapp.breadcrumb import Breadcrumb
from canonical.launchpad.webapp.menu import structured
+from canonical.launchpad.webapp.publisher import LaunchpadView
from canonical.lazr.utils import smartquote
@@ -147,7 +151,7 @@
return Link('+gethelp', 'Help and support options', icon='info')
-class SourcePackageChangeUpstreamStepOne(StepView):
+class SourcePackageChangeUpstreamStepOne(ReturnToReferrerMixin, StepView):
"""A view to set the `IProductSeries` of a sourcepackage."""
schema = Interface
_field_names = []
@@ -171,9 +175,8 @@
IProductSeries['product'], default=default)
self.form_fields += Fields(product_field)
- @property
- def cancel_url(self):
- return canonical_url(self.context)
+ # Override ReturnToReferrerMixin.next_url.
+ next_url = None
def main_action(self, data):
"""See `MultiStepView`."""
@@ -181,7 +184,7 @@
self.request.form['product'] = data['product']
-class SourcePackageChangeUpstreamStepTwo(StepView):
+class SourcePackageChangeUpstreamStepTwo(ReturnToReferrerMixin, StepView):
"""A view to set the `IProductSeries` of a sourcepackage."""
schema = IProductSeries
_field_names = ['product']
@@ -200,10 +203,6 @@
custom_widget('product', DropdownWidget, visible=False)
custom_widget('productseries', LaunchpadRadioWidget)
- @property
- def cancel_url(self):
- return canonical_url(self.context)
-
def setUpFields(self):
super(SourcePackageChangeUpstreamStepTwo, self).setUpFields()
@@ -265,12 +264,16 @@
Fields(display_product_field, productseries_choice)
+ self.form_fields)
+ # Override ReturnToReferrerMixin.next_url until the main_action()
+ # is called.
+ next_url = None
+
main_action_label = u'Change'
def main_action(self, data):
productseries = data['productseries']
# Because it is part of a multistep view, the next_url can't
# be set until the action is called, or it will skip the step.
- self.next_url = canonical_url(self.context)
+ self.next_url = self._return_url
if self.context.productseries == productseries:
# There is nothing to do.
return
@@ -286,7 +289,8 @@
first_step = SourcePackageChangeUpstreamStepOne
-class SourcePackageRemoveUpstreamView(LaunchpadFormView):
+class SourcePackageRemoveUpstreamView(ReturnToReferrerMixin,
+ LaunchpadFormView):
"""A view for removing the link to an upstream package."""
schema = Interface
@@ -294,12 +298,6 @@
label = 'Unlink an upstream project'
page_title = label
- @property
- def cancel_url(self):
- return canonical_url(self.context)
-
- next_url = cancel_url
-
@action('Unlink')
def unlink(self, action, data):
old_series = self.context.productseries
@@ -308,8 +306,8 @@
self.context.sourcepackagename,
self.context.distroseries)
self.request.response.addInfoNotification(
- 'The project %s was unlinked from this source package.' %
- old_series.product.displayname)
+ 'Removed upstream association between %s and %s.' % (
+ old_series.title, self.context.distroseries.displayname))
class SourcePackageView:
@@ -441,6 +439,7 @@
def setUpFields(self):
"""See `LaunchpadFormView`."""
super(SourcePackageAssociationPortletView, self).setUpFields()
+ self.request.annotations['show_edit_buttons'] = True
# Find registered products that are similarly named to the source
# package.
product_vocab = getVocabularyRegistry().get(None, 'Product')
@@ -474,6 +473,10 @@
upstream.displayname)
self.next_url = self.request.getURL()
+
+class SourcePackageUpstreamConnectionsView(LaunchpadView):
+ """A shared view with upstream connection info."""
+
@property
def has_bugtracker(self):
"""Does the product have a bugtracker set?"""
=== modified file 'lib/lp/registry/browser/tests/packaging-views.txt'
--- lib/lp/registry/browser/tests/packaging-views.txt 2010-02-18 18:58:26 +0000
+++ lib/lp/registry/browser/tests/packaging-views.txt 2010-03-03 19:10:21 +0000
@@ -1,4 +1,5 @@
Packaging views
+ irumpy hotter
===============
Packaging links connect a sourcepackage to a distroseries and a productseries.
@@ -273,32 +274,19 @@
>>> print view.label
Linked packages
-The view defines the all_packages property used by the PackagingDeleteView
-to create a vocabulary.
-
- >>> for package in view.all_packaging:
- ... print package.distroseries.name, package.productseries.name
- grumpy hotter
- hoary hotter
-
The view provides the series_packages property that returns a list of
-dicts. Each dict as a series and a list of package dicts. The package dict
-contains the package and field for form actions.
+dicts. Each dict as a series and a list of packages.
- >>> for series_dict in view.series_packages:
- ... print series_dict['series'].name
- ... for package_dict in series_dict['packagings']:
- ... print package_dict['packaging'].distroseries.name
- ... print package_dict['form_id']
- ... print package_dict['field']
+ >>> def print_packages(view):
+ ... for series_dict in view.series_packages:
+ ... print series_dict['series'].name
+ ... for package in series_dict['packagings']:
+ ... print package.distroseries.name
+ >>> print_packages(view)
cold
hotter
grumpy
- delete-grumpy-hot-hotter
-
hoary
- delete-hoary-thunderbird-hotter
-
trunk
The view provides the distro_packaging property that is a list of
@@ -306,40 +294,48 @@
sorted by distribution with Ubuntu first and the rest in alphabetic
order.
- >>> view = create_initialized_view(product, name='+packages')
>>> for distro_dict in view.distro_packaging:
... print distro_dict['distribution'].name
ubuntu
-The +packages named view descends from PackagingDeleteView to provide remove
-link actions for the product's linked packages.
-
- >>> from lp.registry.browser.packaging import PackagingDeleteView
-
- >>> isinstance(view, PackagingDeleteView)
- True
-
A packaging link can be deleted if the owner believes it is an error. The
package linked to hoary is wrong; thunderbird is the wrong sourcepackage.
+ >>> from canonical.launchpad.testing.pages import find_tag_by_id
+ >>> view = create_initialized_view(
+ ... product, name='+packages', principal=a_user)
+ >>> print_packages(view)
+ cold
+ hotter
+ grumpy
+ hoary
+ trunk
+
+ # There are links to the +remove-packaging page.
+ >>> table = find_tag_by_id(view.render(), 'packages-hotter')
+ >>> for link in table.findAll('a'):
+ ... if '+remove-packaging' in link['href']:
+ ... print link['href']
+ http://launchpad.dev/ubuntu/grumpy/+source/hot/+remove-packaging
+ http://launchpad.dev/ubuntu/hoary/+source/thunderbird/+remove-packaging
+
+ >>> [hoary_package] = [
+ ... package for series_dict in view.series_packages
+ ... for package in series_dict['packagings']
+ ... if package.distroseries.name == 'hoary']
+ >>> form = {'field.actions.unlink': 'Unlink'}
+ >>> unlink_view = create_initialized_view(
+ ... hoary_package.sourcepackage, name='+remove-packaging', form=form)
+ >>> unlink_view.errors
+ []
+
+ # The view has to be reloaded since view.series_packages is cached.
>>> view = create_initialized_view(product, name='+packages')
- >>> for package in view.all_packaging:
- ... print package.distroseries.name, package.productseries.name
- grumpy hotter
- hoary hotter
-
- >>> [hoary_package] = [package for package in view.all_packaging
- ... if package.distroseries.name == 'hoary']
- >>> form = {
- ... 'field.packaging': '%s' % hoary_package.id,
- ... 'field.actions.delete_packaging': 'Delete upstream link',
- ... }
- >>> view = create_initialized_view(product, name='+packages', form=form)
- >>> view.errors
- []
- >>> for package in view.all_packaging:
- ... print package.distroseries.name, package.productseries.name
- grumpy hotter
+ >>> print_packages(view)
+ cold
+ hotter
+ grumpy
+ trunk
Distro series +packaging view
=== modified file 'lib/lp/registry/browser/tests/sourcepackage-views.txt'
--- lib/lp/registry/browser/tests/sourcepackage-views.txt 2010-02-27 01:21:37 +0000
+++ lib/lp/registry/browser/tests/sourcepackage-views.txt 2010-03-03 00:38:25 +0000
@@ -218,6 +218,9 @@
Lernid Dev...
+Upstream connections view
+-------------------------
+
The view includes a property for determining if the project has a bug
tracker, though the rules are somewhat complicated.
@@ -233,7 +236,8 @@
>>> package = factory.makeSourcePackage(
... sourcepackagename=sourcepackagename, distroseries=distroseries)
- >>> view = create_initialized_view(package, name='+portlet-associations')
+ >>> view = create_initialized_view(
+ ... package, name='+upstream-connections')
>>> print package.productseries
None
@@ -249,7 +253,8 @@
If a product is not part of a project group and its bug tracker is not
set then the view property is false.
- >>> view = create_initialized_view(package, name='+portlet-associations')
+ >>> view = create_initialized_view(
+ ... package, name='+upstream-connections')
>>> print product.official_malone
False
@@ -319,7 +324,7 @@
>>> for notification in view.request.response.notifications:
... print notification.message
- The project Stinky was unlinked from this source package.
+ Removed upstream association between Stinky stinkyseries series and Wonky.
>>> view = create_initialized_view(package, name='+portlet-associations')
>>> print extract_text(find_tag_by_id(view.render(), 'no-upstreams'))
=== modified file 'lib/lp/registry/browser/tests/test_packaging.py'
--- lib/lp/registry/browser/tests/test_packaging.py 2009-10-23 12:53:21 +0000
+++ lib/lp/registry/browser/tests/test_packaging.py 2010-03-02 23:39:51 +0000
@@ -55,8 +55,10 @@
# Delete the packaging
user_browser = self.user_browser
user_browser.open('http://launchpad.dev/ubuntu/+source/alsa-utils')
- form = user_browser.getForm("delete_warty_alsa-utils_trunk")
- form.getControl(name="field.actions.delete_packaging").click()
+ link = user_browser.getLink(
+ url='/ubuntu/warty/+source/alsa-utils/+remove-packaging')
+ link.click()
+ user_browser.getControl('Unlink').click()
# Check that the change was committed.
login('')
self.assertFalse(packaging_util.packagingEntryExists(
=== modified file 'lib/lp/registry/stories/packaging/xx-distributionsourcepackage-packaging-concurrent-deletion.txt'
--- lib/lp/registry/stories/packaging/xx-distributionsourcepackage-packaging-concurrent-deletion.txt 2009-10-23 12:53:21 +0000
+++ lib/lp/registry/stories/packaging/xx-distributionsourcepackage-packaging-concurrent-deletion.txt 2010-03-02 23:26:49 +0000
@@ -16,33 +16,28 @@
Then the user click the "Delete Link" button in the first tab. The
deletion succeeds and the usual informational message is displayed.
- >>> form = first_browser.getForm("delete_warty_alsa-utils_trunk")
- >>> form.getControl(name="field.actions.delete_packaging").click()
+ >>> link = first_browser.getLink(
+ ... url='/ubuntu/warty/+source/alsa-utils/+remove-packaging')
+ >>> link.click()
+ >>> first_browser.getControl('Unlink').click()
>>> content = first_browser.contents
>>> for tag in find_tags_by_class(content, 'error'):
... print extract_text(tag)
>>> for tag in find_tags_by_class(content, 'informational'):
... print extract_text(tag)
- Removed upstream association between alsa-utils trunk and Warty.
+ Removed upstream association between alsa-utils trunk series and Warty.
A few minutes later, the user sees the same packaging association in the
second tab, and clicks the "Delete Link" button again.
The packaging object has been deleted already, so this action cannot
-succeed. We yield a more useful error message than the mysterious
-"Invalid value" displayed by default.
-
-XXX: We would like to display an informational message and no error
-message, but it would be too much trouble for a corner case like this.
-So we resort to just displaying a helpful error message.
--- David Allouche 2007-12-07
-
- >>> form = second_browser.getForm("delete_warty_alsa-utils_trunk")
- >>> form.getControl(name="field.actions.delete_packaging").click()
+succeed.
+
+ >>> second_browser.getLink(
+ ... url='/ubuntu/warty/+source/alsa-utils/+remove-packaging').click()
>>> content = second_browser.contents
>>> for tag in find_tags_by_class(content, 'informational'):
... print extract_text(tag)
>>> for tag in find_tags_by_class(content, 'error'):
... print extract_text(tag)
- There is 1 error.
This upstream association was deleted already.
=== modified file 'lib/lp/registry/stories/packaging/xx-distributionsourcepackage-packaging.txt'
--- lib/lp/registry/stories/packaging/xx-distributionsourcepackage-packaging.txt 2009-10-23 12:53:21 +0000
+++ lib/lp/registry/stories/packaging/xx-distributionsourcepackage-packaging.txt 2010-03-03 00:25:10 +0000
@@ -15,6 +15,7 @@
The Hoary Hedgehog Release (active development) Set upstream link
1.0.9a-4ubuntu1 release (main) ... weeks ago
The Warty Warthog Release (current stable release) alsa-utils trunk series
+ ...
1.0.8-1ubuntu1 release (main) ... weeks ago
1.0.9a-4 release (main) ... weeks ago
@@ -26,9 +27,10 @@
packaging links.
>>> user_browser.open('http://launchpad.dev/ubuntu/+source/alsa-utils')
- >>> form = user_browser.getForm("delete_warty_alsa-utils_trunk")
- >>> print form.getControl(name="field.actions.delete_packaging")
-
+ >>> link = user_browser.getLink(
+ ... url='/ubuntu/warty/+source/alsa-utils/+remove-packaging')
+ >>> print link
+ >> form = user_browser.getForm("delete_warty_alsa-utils_trunk")
- >>> form.getControl(name="field.actions.delete_packaging").click()
+ >>> link = user_browser.getLink(
+ ... url='/ubuntu/warty/+source/alsa-utils/+remove-packaging')
+ >>> link.click()
+ >>> user_browser.getControl('Unlink').click()
>>> content = user_browser.contents
>>> for tag in find_tags_by_class(content, 'error'):
... print extract_text(tag)
>>> for tag in find_tags_by_class(content, 'informational'):
... print extract_text(tag)
- Removed upstream association between alsa-utils trunk and Warty.
+ Removed upstream association between alsa-utils trunk series and Warty.
>>> print extract_text(find_tag_by_id(content, 'packages_list'))
The Hoary Hedgehog Release (active development) Set upstream link
1.0.9a-4ubuntu1 release (main) ... weeks ago
=== modified file 'lib/lp/registry/stories/packaging/xx-sourcepackage-packaging.txt'
--- lib/lp/registry/stories/packaging/xx-sourcepackage-packaging.txt 2010-02-18 20:41:01 +0000
+++ lib/lp/registry/stories/packaging/xx-sourcepackage-packaging.txt 2010-03-02 23:29:03 +0000
@@ -29,11 +29,9 @@
>>> user_browser.getControl("Change").click()
>>> print extract_text(find_tag_by_id(
... user_browser.contents, 'upstreams'))
- Mozilla Thunderbird ... project
- Project Group: the Mozilla Project
+ the Mozilla Project...Mozilla Thunderbird...trunk...
Bug supervisor: no
Bug tracker: no
- Mozilla Thunderbird trunk series
Branch: no
Translations: no
=== modified file 'lib/lp/registry/stories/product/xx-product-package-pages.txt'
--- lib/lp/registry/stories/product/xx-product-package-pages.txt 2010-01-12 22:34:51 +0000
+++ lib/lp/registry/stories/product/xx-product-package-pages.txt 2010-03-02 22:49:21 +0000
@@ -30,8 +30,8 @@
>>> print extract_text(find_tag_by_id(
... evo_owner.contents, 'packages-trunk'))
Distribution Distribution series Source package Version
- Ubuntu Warty (4.10) evolution
- Ubuntu Hoary (5.04) evolution 1.0
+ Ubuntu Warty (4.10) evolution Remove...
+ Ubuntu Hoary (5.04) evolution 1.0 Remove...
>>> evo_owner.getLink(url='/ubuntu/hoary/+source/evolution') is not None
True
@@ -54,16 +54,19 @@
Packaging links can be deleted if they were created in error.
- >>> form = evo_owner.getForm("delete-warty-evolution-trunk")
- >>> form.getControl(name="field.actions.delete_packaging").click()
- >>> print evo_owner.title
- Linked packages ...
+ >>> evo_owner.getLink(
+ ... url='/ubuntu/warty/+source/evolution/+remove-packaging').click()
+ >>> print evo_owner.title
+ Unlink an upstream project...
+ >>> evo_owner.getControl('Unlink').click()
+ >>> print evo_owner.title
+ Linked packages...
>>> for message in get_feedback_messages(evo_owner.contents):
... print message
- Removed upstream association between Evolution trunk and Warty.
+ Removed upstream association between Evolution trunk series and Warty.
>>> print extract_text(find_tag_by_id(
... evo_owner.contents, 'packages-trunk'))
Distribution Distribution series Source package Version
- Ubuntu Hoary (5.04) evolution 1.0
+ Ubuntu Hoary (5.04) evolution 1.0 Remove...
=== modified file 'lib/lp/registry/stories/productseries/xx-productseries-delete.txt'
--- lib/lp/registry/stories/productseries/xx-productseries-delete.txt 2009-12-14 13:49:03 +0000
+++ lib/lp/registry/stories/productseries/xx-productseries-delete.txt 2010-03-02 23:00:56 +0000
@@ -46,8 +46,10 @@
Mozilla Firefox in Launchpad
>>> owner_browser.getLink('All packages').click()
- >>> owner_browser.getControl(
- ... name='field.actions.delete_packaging', index=1).click()
+ >>> link = owner_browser.getLink(
+ ... url='/ubuntu/warty/+source/mozilla-firefox/+remove-packaging')
+ >>> link.click()
+ >>> owner_browser.getControl('Unlink').click()
Then he returns to delete trunk. He is informed that deletion is permanent,
and that the milestones, releases, and files will also be deleted. The
=== modified file 'lib/lp/registry/templates/distributionsourcepackage-index.pt'
--- lib/lp/registry/templates/distributionsourcepackage-index.pt 2010-02-09 15:38:13 +0000
+++ lib/lp/registry/templates/distributionsourcepackage-index.pt 2010-03-02 23:10:54 +0000
@@ -28,21 +28,6 @@
-
-
- Schema validation errors.
-
-
- Field specific error for the hidden packaging field.
-
- Do you want to remove the upstream link to
- ?
-
-
- Links from distribution packages to upstream project series let
- distribution and upstream maintainers share bugs, patches, and
- translations efficiently.
-
+
+ This upstream association was deleted already.
+
+
+
+
+
+ Do you want to remove the upstream link to
+ ?
+
+
+ Links from distribution packages to upstream project series let
+ distribution and upstream maintainers share bugs, patches, and
+ translations efficiently.
+
+
=== modified file 'lib/lp/registry/templates/sourcepackage-upstream-connections.pt'
--- lib/lp/registry/templates/sourcepackage-upstream-connections.pt 2010-02-26 23:35:06 +0000
+++ lib/lp/registry/templates/sourcepackage-upstream-connections.pt 2010-03-02 20:07:38 +0000
@@ -4,6 +4,10 @@
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
omit-tag="">
+
+ view.request.annotations['show_edit_buttons'] can be set in views
+ that include this page to display the edit and remove buttons.
+
@@ -13,12 +17,12 @@
⇒
-
-
+
+
+
+
=== modified file 'lib/lp/soyuz/stories/soyuz/xx-distroseries-sources.txt'
--- lib/lp/soyuz/stories/soyuz/xx-distroseries-sources.txt 2010-02-15 10:40:56 +0000
+++ lib/lp/soyuz/stories/soyuz/xx-distroseries-sources.txt 2010-03-03 14:00:57 +0000
@@ -72,11 +72,9 @@
Product, Branches, and Bugs:
>>> print extract_text(find_tag_by_id(browser.contents, 'upstreams'))
- Mozilla Firefox ... project
- Project Group: the Mozilla Project
+ the Mozilla Project...Mozilla Firefox...trunk...
Bug supervisor: no
Bug tracker: yes
- Mozilla Firefox trunk series
Branch: no
The user can also download the files for the "currentrelease" (last