> @@ -294,3 +301,49 @@
> """A View to show Answers help."""
>
> page_title = 'Help and support options'
> +
> +
> +class SourcePackageAssociationPortletView(LaunchpadEditFormView):
LaunchpadEditFormView is used to update the context object, which is not
the case here; it is creating Packaging object though an indirect method.
Why was this base class used instead of LaunchpadFormView? It is because
it can be used to update the Packaging object after it is set? If so,
the view will have to be registered on IPackaging, which does not exist in
this scenario.
> + """A view for linking to an upstream package."""
> +
> + schema = Interface
> + custom_widget(
> + 'upstream', LaunchpadRadioWidget, orientation='vertical')
> + product_suggestions = None
> +
> + def setUpFields(self):
> + """See `LaunchpadFormView`."""
> + super(SourcePackageAssociationPortletView, self).setUpFields()
> + # Find registered products that are similarly named to the source
> + # package.
> + product_vocab = getVocabularyRegistry().get(None, 'Product')
> + matches = product_vocab.searchForTerms(self.context.name)
> + # Based upon the matching products, create a new vocabulary with
> + # term descriptions that include a link to the product.
> + self.product_suggestions = []
> + vocab_terms = []
> + for item in matches:
> + product = item.value
> + self.product_suggestions.append(product)
> + item_url = canonical_url(product)
> + description = """<a href="%s">%s</a>""" % (
> + item_url, product.displayname)
I think this needs escaping. product.displayname may contain [?><].
I have been pondering cases where we need to be clear that we are showing
*registered* launchpad projects. Many of the confusing-ui issues is that users
do not understand that someone must register the project for it to be used.
Does the use of *registered* provide a clue that someone may need to register
the upstream project to complete the task?
I would have made the underline the same width as the heading.
...
@@ -96,3 +98,65 @@
>>> print view.request.response.notifications
[]
+
+Upstream associations portlet
+-----------------------------
+
+The upstreams associations portlet either displays the upstream
+information if it is already set or gives the user the opportunity to
+suggest the association. The suggestion is based on a
+ProductVocabulary query using the source package name.
+
+Since the bonkers source project was associated previously with the
+bonkers project, the portlet will display that information.
+
+ >>> view = create_initialized_view(package, name='+portlet-associations')
+ >>> for product in view.product_suggestions:
+ ... print product.name
+ bonkers
+
+ >>> from canonical.launchpad.testing.pages import (
+ ... extract_text, find_tag_by_id)
+ >>> content = extract_text(find_tag_by_id(view.render(), 'upstreams'))
+ >>> print content
+ Project:...Bonkers...
+ Series:...crazy...
+
+A new source project that is not linked to an upstream will result in
+the portlet showing the suggested project.
+
+ >>> product = factory.makeProduct(name='lernid', displayname='Lernid')
+ >>> sourcepackagename = factory.makeSourcePackageName(name='lernid')
+ >>> package = factory.makeSourcePackage(
+ ... sourcepackagename=sourcepackagename, distroseries=distroseries)
+
+ >>> view = create_initialized_view(package, name='+portlet-associations')
+ >>> for product in view.product_suggestions:
+ ... print product.name
+ lernid
+
+ >>> content = extract_text(find_tag_by_id(view.render(), 'no-upstreams'))
+ >>> print content
+ Launchpad doesn’t know which project and series this
+ package belongs to. ...
+ Is the following project the upstream for this source package?
+ Upstream project:
+ Lernid...
+
+If there are multiple potential matches they are all shown.
+
+ >>> product = factory.makeProduct(name='lernid-dev', displayname='Lernid Dev')
+ >>> view = create_initialized_view(package, name='+portlet-associations')
+ >>> for product in view.product_suggestions:
+ ... print product.name
+ lernid
+ lernid-dev
+
+ >>> content = extract_text(find_tag_by_id(view.render(), 'no-upstreams'))
+ >>> print content
+ Launchpad doesn’t know which project and series this
+ package belongs to. ...
+ Is one of these projects the upstream for this source package?
+ Upstream project:
+ Lernid...
+ Lernid Dev...
While I do not think there is a issue with using the portlet class here, it
can present portability issues when if it is reused on other pages, perhaps
the DistributionSourcePackage. I think it is safer to define the class in the
callsite.
...
+ <tal:has_no_series condition="not: series">
+ <div id="no-upstreams" tal:condition="view/product_suggestions">
+ <p>
+ Launchpad doesn’t know which project and series this
+ package belongs to. Links from distribution packages to
+ upstream project let distribution and upstream
+ maintainers share bugs, patches, and translations
+ efficiently.
+ </p>
+ <div tal:condition="python: len(view.product_suggestions) > 1">
+ <b>Is one of these projects the upstream for this source
+ package?</b>
+ </div>
+ <div tal:condition="python: len(view.product_suggestions) == 1">
+ <b>Is the following project the upstream for this source package?</b>
+ </div>
I see my favourite plural problem has mutated. There must be some ironic god
at work hear because I have an unlanded branch that introduces a plural macro
that adds a suffix if the count is not 1. My solution will not work in this
case. I just want to keep these python hacks out of the code. I can certainly
modify my macro to support singular and plural phrases instead of suffixes.
We can collaborate on this. This is what I have queued to land in
base-layout-macros.pt.
<metal:plural define-macro="plural"><tal:comment condition="nothing">
This macro requires the call site to define `count` in a containing
tag or as a global. The plural `suffix` can also be defined by the
containing tag or as a global, the default is 's'.
</tal:comment><tal:if
define="
l_default string:s;
l_suffix suffix | l_default;"
condition="python: count != 1"
replace="l_suffix" />
</metal:plural>
</macros>
..
=== modified file 'lib/lp/ registry/ browser/ sourcepackage. py' registry/ browser/ sourcepackage. py 2009-12-18 13:25:19 +0000 registry/ browser/ sourcepackage. py 2010-01-25 23:25:27 +0000
--- lib/lp/
+++ lib/lp/
...
> @@ -294,3 +301,49 @@ sociationPortle tView(Launchpad EditFormView) :
> """A View to show Answers help."""
>
> page_title = 'Help and support options'
> +
> +
> +class SourcePackageAs
LaunchpadEditFo rmView is used to update the context object, which is not
the case here; it is creating Packaging object though an indirect method.
Why was this base class used instead of LaunchpadFormView? It is because
it can be used to update the Packaging object after it is set? If so,
the view will have to be registered on IPackaging, which does not exist in
this scenario.
> + """A view for linking to an upstream package.""" idget, orientation= 'vertical' ) iew`."" " kageAssociation PortletView, self).setUpFields() gistry( ).get(None, 'Product') vocab.searchFor Terms(self. context. name) suggestions = [] suggestions. append( product) url(product) displayname)
> +
> + schema = Interface
> + custom_widget(
> + 'upstream', LaunchpadRadioW
> + product_suggestions = None
> +
> + def setUpFields(self):
> + """See `LaunchpadFormV
> + super(SourcePac
> + # Find registered products that are similarly named to the source
> + # package.
> + product_vocab = getVocabularyRe
> + matches = product_
> + # Based upon the matching products, create a new vocabulary with
> + # term descriptions that include a link to the product.
> + self.product_
> + vocab_terms = []
> + for item in matches:
> + product = item.value
> + self.product_
> + item_url = canonical_
> + description = """<a href="%s">%s</a>""" % (
> + item_url, product.
I think this needs escaping. product.displayname may contain [?><].
> + vocab_terms. append( SimpleTerm( product, product.name, description)) y(vocab_ terms) __name_ _='upstream' ,
> + upstream_vocabulary = SimpleVocabular
> +
> + self.form_fields = Fields(
> + Choice(
> + title=_('Upstream project'),
I have been pondering cases where we need to be clear that we are showing
*registered* launchpad projects. Many of the confusing-ui issues is that users
do not understand that someone must register the project for it to be used.
Does the use of *registered* provide a clue that someone may need to register
the upstream project to complete the task?
> + default=None, upstream_ vocabulary, _("Select the upstream project"),
> + vocabulary=
> + #description=
I suppose this is not needed.
> + required=True)) 'upstream' ) setPackaging( upstream. development_ focus, self.user) response. addInfoNotifica tion( displayname) getURL( )
> +
> + @action('Link to Upstream Project', name='link')
> + def link(self, action, data):
> + upstream = data.get(
> + self.context.
> + self.request.
> + 'The project %s was linked to this source package.' %
> + upstream.
> + self.next_url = self.request.
> === modified file 'lib/lp/ registry/ browser/ tests/sourcepac kage-views. txt' registry/ browser/ tests/sourcepac kage-views. txt 2009-10-27 04:04:55 +0000 registry/ browser/ tests/sourcepac kage-views. txt 2010-01-25 23:25:27 +0000 ------- ------- ---
> --- lib/lp/
> +++ lib/lp/
> @@ -1,6 +1,8 @@
> SourcePackage views
> ===================
>
> +Edit packaging view
> +------
I would have made the underline the same width as the heading.
...
@@ -96,3 +98,65 @@
>>> print view.request. response. notifications ------- ------- ------- -- initialized_ view(package, name='+ portlet- associations' ) suggestions: launchpad. testing. pages import ( text(find_ tag_by_ id(view. render( ), 'upstreams')) ...Bonkers. .. makeProduct( name='lernid' , displayname= 'Lernid' ) makeSourcePacka geName( name='lernid' ) makeSourcePacka ge( me=sourcepackag ename, distroseries= distroseries) initialized_ view(package, name='+ portlet- associations' ) suggestions: text(find_ tag_by_ id(view. render( ), 'no-upstreams')) makeProduct( name='lernid- dev', displayname='Lernid Dev') initialized_ view(package, name='+ portlet- associations' ) suggestions: text(find_ tag_by_ id(view. render( ), 'no-upstreams'))
[]
+
+Upstream associations portlet
+------
+
+The upstreams associations portlet either displays the upstream
+information if it is already set or gives the user the opportunity to
+suggest the association. The suggestion is based on a
+ProductVocabulary query using the source package name.
+
+Since the bonkers source project was associated previously with the
+bonkers project, the portlet will display that information.
+
+ >>> view = create_
+ >>> for product in view.product_
+ ... print product.name
+ bonkers
+
+ >>> from canonical.
+ ... extract_text, find_tag_by_id)
+ >>> content = extract_
+ >>> print content
+ Project:
+ Series:...crazy...
+
+A new source project that is not linked to an upstream will result in
+the portlet showing the suggested project.
+
+ >>> product = factory.
+ >>> sourcepackagename = factory.
+ >>> package = factory.
+ ... sourcepackagena
+
+ >>> view = create_
+ >>> for product in view.product_
+ ... print product.name
+ lernid
+
+ >>> content = extract_
+ >>> print content
+ Launchpad doesn’t know which project and series this
+ package belongs to. ...
+ Is the following project the upstream for this source package?
+ Upstream project:
+ Lernid...
+
+If there are multiple potential matches they are all shown.
+
+ >>> product = factory.
+ >>> view = create_
+ >>> for product in view.product_
+ ... print product.name
+ lernid
+ lernid-dev
+
+ >>> content = extract_
+ >>> print content
+ Launchpad doesn’t know which project and series this
+ package belongs to. ...
+ Is one of these projects the upstream for this source package?
+ Upstream project:
+ Lernid...
+ Lernid Dev...
...
> === modified file 'lib/lp/ registry/ templates/ sourcepackage- index.pt' registry/ templates/ sourcepackage- index.pt 2009-12-03 16:54:29 +0000 registry/ templates/ sourcepackage- index.pt 2010-01-25 23:25:27 +0000
> --- lib/lp/
> +++ lib/lp/
...
> + <tal:porlet replace="structure context/ @@+portlet- associations" />
mis-spelling? See my next remark. I would use:
<div class="portlet" content="structure context/ @@+portlet- associations" />
> === added file 'lib/lp/ registry/ templates/ sourcepackage- portlet- associations. pt' registry/ templates/ sourcepackage- portlet- associations. pt 1970-01-01 00:00:00 +0000 registry/ templates/ sourcepackage- portlet- associations. pt 2010-01-25 23:25:27 +0000 xml.zope. org/namespaces/ tal" xml.zope. org/namespaces/ metal" xml.zope. org/namespaces/ i18n" associations" >
> --- lib/lp/
> +++ lib/lp/
> @@ -0,0 +1,86 @@
> +<tal:root
> + xmlns:tal="http://
> + xmlns:metal="http://
> + xmlns:i18n="http://
> + omit-tag="">
> +
> + <div class="portlet" id="portlet-
While I do not think there is a issue with using the portlet class here, it rcePackage. I think it is safer to define the class in the
can present portability issues when if it is reused on other pages, perhaps
the DistributionSou
callsite.
...
+ <tal:has_no_series condition="not: series"> "view/product_ suggestions" > "python: len(view. product_ suggestions) > 1"> "python: len(view. product_ suggestions) == 1">
+ <div id="no-upstreams" tal:condition=
+ <p>
+ Launchpad doesn’t know which project and series this
+ package belongs to. Links from distribution packages to
+ upstream project let distribution and upstream
+ maintainers share bugs, patches, and translations
+ efficiently.
+ </p>
+ <div tal:condition=
+ <b>Is one of these projects the upstream for this source
+ package?</b>
+ </div>
+ <div tal:condition=
+ <b>Is the following project the upstream for this source package?</b>
+ </div>
I see my favourite plural problem has mutated. There must be some ironic god
at work hear because I have an unlanded branch that introduces a plural macro
that adds a suffix if the count is not 1. My solution will not work in this
case. I just want to keep these python hacks out of the code. I can certainly
modify my macro to support singular and plural phrases instead of suffixes.
We can collaborate on this. This is what I have queued to land in macros. pt.
base-layout-
<metal:plural define- macro=" plural" ><tal:comment condition= "nothing" > comment> <tal:if "python: count != 1" "l_suffix" />
This macro requires the call site to define `count` in a containing
tag or as a global. The plural `suffix` can also be defined by the
containing tag or as a global, the default is 's'.
</tal:
define="
l_default string:s;
l_suffix suffix | l_default;"
condition=
replace=
</metal:plural>
</macros>
...