launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #10524
[Merge] lp:~wgrant/launchpad/rebuild-projectgroup-filebug into lp:launchpad
William Grant has proposed merging lp:~wgrant/launchpad/rebuild-projectgroup-filebug into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #1031210 in Launchpad itself: "ProjectGroup:+filebug doesn't really know what it is meant to be"
https://bugs.launchpad.net/launchpad/+bug/1031210
For more details, see:
https://code.launchpad.net/~wgrant/launchpad/rebuild-projectgroup-filebug/+merge/117835
This branch cleans up some of +filebug's horrors. In particular, it removes the core FileBugViewBase's support for its non-IBugTarget instantiations: IMaloneApplication and IProjectGroup.
The contextless IMaloneApplication:+filebug view was deregistered in 2009, but remnants persist.
ProjectGroup:+filebug has a long and sad history. Once upon a time it was a set of normal forms with a project <select>. Then it was AJAXified like Product:+filebug, retrieving the project-specific bits of the form using a separate request once the project was chosen. But that got too complicated to be worth it, until the JS was changed early last year to just redirect to Product:+filebug once a project was selected. I've split it out into a separate view class, made the classical form redirect to Product:+filebug, and dropped the JS support. This leaves the view in a workable but low-maintenance state, and lets major cleanups happen in the more traditional +filebug views.
--
https://code.launchpad.net/~wgrant/launchpad/rebuild-projectgroup-filebug/+merge/117835
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/rebuild-projectgroup-filebug into lp:launchpad.
=== modified file 'lib/lp/bugs/browser/bugtarget.py'
--- lib/lp/bugs/browser/bugtarget.py 2012-08-01 01:05:08 +0000
+++ lib/lp/bugs/browser/bugtarget.py 2012-08-02 08:44:19 +0000
@@ -16,7 +16,7 @@
"IProductBugConfiguration",
"OfficialBugTagsManageView",
"ProductConfigureBugTrackerView",
- "ProjectFileBugGuidedView",
+ "ProjectGroupFileBugGuidedView",
"product_to_productbugconfiguration",
]
@@ -105,7 +105,6 @@
UNRESOLVED_BUGTASK_STATUSES,
)
from lp.bugs.interfaces.bugtracker import IBugTracker
-from lp.bugs.interfaces.malone import IMaloneApplication
from lp.bugs.interfaces.securitycontact import IHasSecurityContact
from lp.bugs.model.bugtask import BugTask
from lp.bugs.model.structuralsubscription import (
@@ -149,7 +148,6 @@
from lp.services.webapp.authorization import check_permission
from lp.services.webapp.batching import BatchNavigator
from lp.services.webapp.breadcrumb import Breadcrumb
-from lp.services.webapp.interfaces import ILaunchBag
from lp.services.webapp.menu import structured
# A simple vocabulary for the subscribe_to_existing_bug form field.
@@ -253,12 +251,9 @@
custom_widget('information_type', LaunchpadRadioWidgetWithDescription)
extra_data_token = None
- advanced_form = False
- frontpage_form = False
- data_parser = None
def __init__(self, context, request):
- LaunchpadFormView.__init__(self, context, request)
+ super(FileBugViewBase, self).__init__(context, request)
self.extra_data = FileBugData()
def initialize(self):
@@ -282,15 +277,12 @@
type.name for type in PRIVATE_INFORMATION_TYPES]
cache.objects['bug_private_by_default'] = (
IProduct.providedBy(self.context) and self.context.private_bugs)
- # Project groups are special. The Next button sends you to
- # Product:+filebug, so we need none of the usual stuff.
- if not IProjectGroup.providedBy(self.context):
- cache.objects['information_type_data'] = [
- {'value': term.name, 'description': term.description,
- 'name': term.title,
- 'description_css_class': 'choice-description'}
- for term in
- self.context.pillar.getAllowedBugInformationTypes()]
+ cache.objects['information_type_data'] = [
+ {'value': term.name, 'description': term.description,
+ 'name': term.title,
+ 'description_css_class': 'choice-description'}
+ for term in
+ self.context.pillar.getAllowedBugInformationTypes()]
bugtask_status_data = vocabulary_to_choice_edit_items(
BugTaskStatus, include_description=True, css_class_prefix='status',
excluded_items=[
@@ -307,8 +299,7 @@
excluded_items=[BugTaskImportance.UNKNOWN])
cache.objects['bugtask_importance_data'] = bugtask_importance_data
cache.objects['enable_bugfiling_duplicate_search'] = (
- IProjectGroup.providedBy(self.context)
- or self.context.enable_bugfiling_duplicate_search)
+ self.context.enable_bugfiling_duplicate_search)
super(FileBugViewBase, self).initialize()
@@ -366,21 +357,8 @@
if (IDistribution.providedBy(context) or
IDistributionSourcePackage.providedBy(context)):
field_names.append('packagename')
- elif IMaloneApplication.providedBy(context):
- field_names.append('bugtarget')
- elif IProjectGroup.providedBy(context):
- field_names.append('product')
- elif not IProduct.providedBy(context):
- raise AssertionError('Unknown context: %r' % context)
-
- # If the context is a project group we want to render the optional
- # fields since they will initially be hidden and later exposed if the
- # selected project supports them.
- include_extra_fields = IProjectGroup.providedBy(context)
- if not include_extra_fields:
- include_extra_fields = self.is_bug_supervisor
-
- if include_extra_fields:
+
+ if self.is_bug_supervisor:
field_names.extend(
['assignee', 'importance', 'milestone', 'status'])
@@ -405,14 +383,11 @@
return IProduct.providedBy(self.context)
def contextIsProject(self):
- return IProjectGroup.providedBy(self.context)
+ return False
def targetIsUbuntu(self):
ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
- return (self.context == ubuntu or
- (IMaloneApplication.providedBy(self.context) and
- self.request.form.get('field.bugtarget.distribution') ==
- ubuntu.name))
+ return self.context == ubuntu
def getPackageNameFieldCSSClass(self):
"""Return the CSS class for the packagename field."""
@@ -455,8 +430,6 @@
if packagename:
if IDistribution.providedBy(self.context):
distribution = self.context
- elif 'distribution' in data:
- distribution = data['distribution']
else:
assert IDistributionSourcePackage.providedBy(self.context)
distribution = self.context.distribution
@@ -479,17 +452,6 @@
self.setFieldError("packagename",
"Please enter a package name")
- # If we've been called from the frontpage filebug forms we must check
- # that whatever product or distro is having a bug filed against it
- # actually uses Malone for its bug tracking.
- product_or_distro = self.getProductOrDistroFromContext()
- if (product_or_distro is not None and
- product_or_distro.bug_tracking_usage != ServiceUsage.LAUNCHPAD):
- self.setFieldError(
- 'bugtarget',
- "%s does not use Launchpad as its bug tracker " %
- product_or_distro.displayname)
-
def setUpWidgets(self):
"""Customize the onKeyPress event of the package name chooser."""
super(FileBugViewBase, self).setUpWidgets()
@@ -502,11 +464,6 @@
"""Set up the form fields. See `LaunchpadFormView`."""
super(FileBugViewBase, self).setUpFields()
- # Project groups are special. The Next button sends you to
- # Product:+filebug, so we need none of the usual stuff.
- if IProjectGroup.providedBy(self.context):
- return
-
if self.is_bug_supervisor:
info_type_vocab = InformationTypeVocabulary(
types=self.context.pillar.getAllowedBugInformationTypes())
@@ -534,14 +491,8 @@
def contextUsesMalone(self):
"""Does the context use Malone as its official bugtracker?"""
- if IProjectGroup.providedBy(self.context):
- products_using_malone = [
- product for product in self.context.products
- if product.bug_tracking_usage == ServiceUsage.LAUNCHPAD]
- return len(products_using_malone) > 0
- else:
- bug_tracking_usage = self.getMainContext().bug_tracking_usage
- return bug_tracking_usage == ServiceUsage.LAUNCHPAD
+ bug_tracking_usage = self.getMainContext().bug_tracking_usage
+ return bug_tracking_usage == ServiceUsage.LAUNCHPAD
def shouldSelectPackageName(self):
"""Should the radio button to select a package be selected?"""
@@ -559,8 +510,6 @@
title = data["title"]
comment = data["comment"].rstrip()
packagename = data.get("packagename")
- distribution = data.get(
- "distribution", getUtility(ILaunchBag).distribution)
information_type = data.get("information_type")
# If the old UI is enabled, security bugs are always embargoed
@@ -569,14 +518,6 @@
information_type = InformationType.PRIVATESECURITY
context = self.context
- if distribution is not None:
- # We're being called from the generic bug filing form, so
- # manually set the chosen distribution as the context.
- context = distribution
- elif IProjectGroup.providedBy(context):
- context = data['product']
- elif IMaloneApplication.providedBy(context):
- context = data['bugtarget']
# Ensure that no package information is used, if the user
# enters a package name but then selects "I don't know".
@@ -814,22 +755,8 @@
return self, ()
def getProductOrDistroFromContext(self):
- """Return the product or distribution relative to the context.
-
- For instance, if the context is an IDistroSeries, return the
- distribution related to it. Will return None if the context is
- not related to a product or a distro.
- """
- context = self.context
- if IProduct.providedBy(context) or IDistribution.providedBy(context):
- return context
- elif IProductSeries.providedBy(context):
- return context.product
- elif (IDistroSeries.providedBy(context) or
- IDistributionSourcePackage.providedBy(context)):
- return context.distribution
- else:
- return None
+ """Return the product or distribution relative to the context."""
+ return self.context.pillar
def showOptionalMarker(self, field_name):
"""See `LaunchpadFormView`."""
@@ -854,26 +781,11 @@
total accuracy, and will return the first 'relevant' bugtask
it finds even if there are other candidates. Be warned!
"""
- context = self.context
-
- if IProjectGroup.providedBy(context):
- contexts = set(context.products)
- else:
- contexts = [context]
-
for bugtask in bug.bugtasks:
- if bugtask.target in contexts or bugtask.pillar in contexts:
+ if self.context in (bugtask.target, bugtask.pillar):
return bugtask
return None
- @property
- def bugtarget(self):
- """The bugtarget we're currently assuming.
-
- The same as the context.
- """
- return self.context
-
default_bug_reported_acknowledgement = "Thank you for your bug report."
def getAcknowledgementMessage(self, context):
@@ -947,38 +859,24 @@
Returns a list of dicts, with each dict containing values for
"preamble" and "content".
"""
-
- def target_name(target):
- # IProjectGroup can be considered the target of a bug during
- # the bug filing process, but does not extend IBugTarget
- # and ultimately cannot actually be the target of a
- # bug. Hence this function to determine a suitable
- # name/title to display. Hurrumph.
- if IBugTarget.providedBy(target):
- return target.bugtargetdisplayname
- else:
- return target.displayname
-
guidelines = []
- bugtarget = self.context
- if bugtarget is not None:
- content = bugtarget.bug_reporting_guidelines
+ content = self.context.bug_reporting_guidelines
+ if content is not None and len(content) > 0:
+ guidelines.append({
+ "source": self.context.bugtargetdisplayname,
+ "content": content,
+ })
+ # Distribution source packages are shown with both their
+ # own reporting guidelines and those of their
+ # distribution.
+ if IDistributionSourcePackage.providedBy(self.context):
+ distribution = self.context.distribution
+ content = distribution.bug_reporting_guidelines
if content is not None and len(content) > 0:
guidelines.append({
- "source": target_name(bugtarget),
- "content": content,
- })
- # Distribution source packages are shown with both their
- # own reporting guidelines and those of their
- # distribution.
- if IDistributionSourcePackage.providedBy(bugtarget):
- distribution = bugtarget.distribution
- content = distribution.bug_reporting_guidelines
- if content is not None and len(content) > 0:
- guidelines.append({
- "source": target_name(distribution),
- "content": content,
- })
+ "source": distribution.bugtargetdisplayname,
+ "content": content,
+ })
return guidelines
def getMainContext(self):
@@ -995,7 +893,7 @@
context, self.user)
-class FileBugAdvancedView(FileBugViewBase):
+class FileBugAdvancedView(LaunchpadView):
"""Browser view for filing a bug.
This view exists only to redirect from +filebug-advanced to +filebug.
@@ -1038,11 +936,6 @@
return url
@property
- def search_context(self):
- """Return the context used to search for similar bugs."""
- return self.context
-
- @property
def search_text(self):
"""Return the search string entered by the user."""
return self.request.get('title')
@@ -1053,19 +946,16 @@
title = self.search_text
if not title:
return []
- search_context = self.search_context
- if search_context is None:
- return []
- elif IProduct.providedBy(search_context):
- context_params = {'product': search_context}
- elif IDistribution.providedBy(search_context):
- context_params = {'distribution': search_context}
+ elif IProduct.providedBy(self.context):
+ context_params = {'product': self.context}
+ elif IDistribution.providedBy(self.context):
+ context_params = {'distribution': self.context}
else:
- assert IDistributionSourcePackage.providedBy(search_context), (
- 'Unknown search context: %r' % search_context)
+ assert IDistributionSourcePackage.providedBy(self.context), (
+ 'Unknown search context: %r' % self.context)
context_params = {
- 'distribution': search_context.distribution,
- 'sourcepackagename': search_context.sourcepackagename}
+ 'distribution': self.context.distribution,
+ 'sourcepackagename': self.context.sourcepackagename}
matching_bugtasks = getUtility(IBugTaskSet).findSimilar(
self.user, title, **context_params)
@@ -1118,23 +1008,10 @@
@property
def page_title(self):
- if IMaloneApplication.providedBy(self.context):
- return 'Report a bug'
- else:
- return 'Report a bug about %s' % self.context.title
-
- @safe_action
- @action("Continue", name="projectgroupsearch",
- validator="validate_search")
- def projectgroup_search_action(self, action, data):
- """Search for similar bug reports."""
- # Don't give focus to any widget, to ensure that the browser
- # won't scroll past the "possible duplicates" list.
- self.initial_focus_widget = None
- return self._PROJECTGROUP_SEARCH_FOR_DUPES()
-
- @safe_action
- @action("Continue", name="search", validator="validate_search")
+ return 'Report a bug about %s' % self.context.title
+
+ @safe_action
+ @action("Continue", name="search")
def search_action(self, action, data):
"""Search for similar bug reports."""
# Don't give focus to any widget, to ensure that the browser
@@ -1143,26 +1020,6 @@
return self.showFileBugForm()
@property
- def search_context(self):
- """Return the context used to search for similar bugs."""
- if IDistributionSourcePackage.providedBy(self.context):
- return self.context
-
- search_context = self.getMainContext()
- if IProjectGroup.providedBy(search_context):
- assert self.widgets['product'].hasValidInput(), (
- "This method should be called only when we know which"
- " product the user selected.")
- search_context = self.widgets['product'].getInputValue()
- elif IMaloneApplication.providedBy(search_context):
- if self.widgets['bugtarget'].hasValidInput():
- search_context = self.widgets['bugtarget'].getInputValue()
- else:
- search_context = None
-
- return search_context
-
- @property
def search_text(self):
"""Return the search string entered by the user."""
try:
@@ -1170,18 +1027,6 @@
except InputErrors:
return None
- def validate_search(self, action, data):
- """Make sure some keywords are provided."""
- try:
- data['title'] = self.widgets['title'].getInputValue()
- except InputErrors as error:
- self.setFieldError("title", "A summary is required.")
- return [error]
-
- # Return an empty list of errors to satisfy the validation API,
- # and say "we've handled the validation and found no errors."
- return []
-
def validate_no_dupe_found(self, action, data):
return ()
@@ -1195,13 +1040,24 @@
return self._FILEBUG_FORM()
-class ProjectFileBugGuidedView(FileBugGuidedView):
+class ProjectGroupFileBugGuidedView(LaunchpadFormView):
"""Guided filebug pages for IProjectGroup."""
- # Make inheriting the base class' actions work.
- actions = FileBugGuidedView.actions
schema = IProjectGroupBugAddForm
+ custom_widget('title', TextWidget, displayWidth=40)
+ custom_widget('tags', BugTagsWidget)
+
+ extra_data_to_process = False
+
+ @property
+ def field_names(self):
+ return ['product', 'title', 'tags']
+
+ @property
+ def page_title(self):
+ return 'Report a bug about %s' % self.context.title
+
@cachedproperty
def products_using_malone(self):
return [
@@ -1215,36 +1071,30 @@
else:
return None
- @property
- def inline_filebug_form_url(self):
- """Return the URL to the inline filebug form.
-
- If a token was passed to this view, it will be passed through
- to the inline bug filing form via the returned URL.
-
- The URL returned will be the URL of the first of the current
- ProjectGroup's products, since that's the product that will be
- selected by default when the view is rendered.
- """
- url = canonical_url(
- self.default_product, view_name='+filebug-inline-form')
- if self.extra_data_token is not None:
- url = urlappend(url, self.extra_data_token)
- return url
-
- @property
- def duplicate_search_url(self):
- """Return the URL to the inline duplicate search view.
-
- The URL returned will be the URL of the first of the current
- ProjectGroup's products, since that's the product that will be
- selected by default when the view is rendered.
- """
- url = canonical_url(
- self.default_product, view_name='+filebug-show-similar')
- if self.extra_data_token is not None:
- url = urlappend(url, self.extra_data_token)
- return url
+ def contextUsesMalone(self):
+ return self.default_product is not None
+
+ def contextIsProduct(self):
+ return False
+
+ def contextIsProject(self):
+ return True
+
+ def getProductOrDistroFromContext(self):
+ return None
+
+ @safe_action
+ @action("Continue", name="projectgroupsearch")
+ def projectgroup_search_action(self, action, data):
+ """Redirect to the chosen product's form."""
+ base = canonical_url(data['product'], view_name='+filebug')
+ query = urllib.urlencode([
+ ('field.actions.search', 'Continue'),
+ ('field.title', data['title']),
+ ('field.tags', ' '.join(data['tags'])),
+ ])
+ url = '%s?%s' % (base, query)
+ self.request.response.redirect(url)
class BugTargetBugListingView(LaunchpadView):
=== modified file 'lib/lp/bugs/browser/configure.zcml'
--- lib/lp/bugs/browser/configure.zcml 2012-07-31 03:14:11 +0000
+++ lib/lp/bugs/browser/configure.zcml 2012-08-02 08:44:19 +0000
@@ -422,7 +422,8 @@
<browser:page
name="+filebug"
for="lp.registry.interfaces.projectgroup.IProjectGroup"
- class="lp.bugs.browser.bugtarget.ProjectFileBugGuidedView"
+ class="lp.bugs.browser.bugtarget.ProjectGroupFileBugGuidedView"
+ template="../templates/bugtarget-filebug-search.pt"
permission="launchpad.AnyPerson"/>
<browser:page
name="+filebug-advanced"
=== modified file 'lib/lp/bugs/browser/tests/bugtarget-filebug-views.txt'
--- lib/lp/bugs/browser/tests/bugtarget-filebug-views.txt 2012-07-30 23:49:34 +0000
+++ lib/lp/bugs/browser/tests/bugtarget-filebug-views.txt 2012-08-02 08:44:19 +0000
@@ -79,20 +79,6 @@
>>> print filebug_view.duplicate_search_url
http://launchpad.dev/firefox/+filebug-show-similar
-For project groups, the URLs returned will refer to the default product
-for those project groups.
-
- >>> from lp.registry.interfaces.projectgroup import IProjectGroupSet
- >>> gnome_project = getUtility(IProjectGroupSet).getByName('gnome')
- >>> gnome_filebug_view = create_initialized_view(
- ... gnome_project, '+filebug')
-
- >>> print gnome_filebug_view.inline_filebug_form_url
- http://launchpad.dev/evolution/+filebug-inline-form
-
- >>> print gnome_filebug_view.duplicate_search_url
- http://launchpad.dev/evolution/+filebug-show-similar
-
Adding extra info to filed bugs
-------------------------------
=== modified file 'lib/lp/bugs/javascript/filebug_dupefinder.js'
--- lib/lp/bugs/javascript/filebug_dupefinder.js 2012-07-23 11:15:20 +0000
+++ lib/lp/bugs/javascript/filebug_dupefinder.js 2012-08-02 08:44:19 +0000
@@ -314,43 +314,20 @@
}
/**
- * Use the value of the product field to set the relevant urls elements.
- */
-function set_product_urls()
-{
- var product_field = Y.one(Y.DOM.byId('field.product'));
- if (Y.Lang.isValue(product_field)) {
- var product = product_field.get('value');
- search_url_base =
- filebug_base_url + product + '/+filebug-show-similar';
- var submit_url = [product, '+filebug'].join('/');
- var search_form = Y.one('#filebug-search-form');
- search_form.setAttribute('action', filebug_base_url+submit_url);
- }
-}
-
-/**
* Set up the dupe finder, overriding the default behaviour of the
* +filebug search form.
*/
function set_up_dupe_finder(transaction_id, response, args) {
// Grab the inline filebug base url and store it.
filebug_base_url = Y.one('#filebug-base-url').getAttribute('href');
-
- // Set up the product field change listener and related variables.
- namespace.setup_product_urls();
-
+ search_url_base = Y.one('#duplicate-search-url').getAttribute('href');
+
+ search_button = Y.one(Y.DOM.byId('field.actions.search'));
search_field = Y.one(Y.DOM.byId('field.title'));
- var product_field = Y.one(Y.DOM.byId('field.product'));
- if (Y.Lang.isValue(product_field)) {
- Y.one(
- Y.DOM.byId('field.actions.projectgroupsearch')).set(
- 'value', 'Next');
- } else {
+ if (Y.Lang.isValue(search_button)) {
// Update the label on the search button so that it no longer
// says "Continue".
- search_button = Y.one(Y.DOM.byId('field.actions.search'));
search_button.set('value', 'Next');
// Change the name and id of the search field so that it doesn't
@@ -459,16 +436,6 @@
});
};
-namespace.setup_product_urls = function() {
- // Grab the search_url_base value from the page and store it.
- search_url_base = Y.one('#duplicate-search-url').getAttribute('href');
- var product_field = Y.one(Y.DOM.byId('field.product'));
- if (Y.Lang.isValue(product_field)) {
- set_product_urls();
- product_field.on('change', set_product_urls);
- }
-};
-
namespace.setup_dupe_finder = function() {
var config = {on: {success: set_up_dupe_finder,
failure: function() {}}};
=== modified file 'lib/lp/bugs/javascript/tests/test_filebug_dupefinder.js'
--- lib/lp/bugs/javascript/tests/test_filebug_dupefinder.js 2012-06-28 16:54:20 +0000
+++ lib/lp/bugs/javascript/tests/test_filebug_dupefinder.js 2012-08-02 08:44:19 +0000
@@ -242,86 +242,6 @@
Y.Assert.areEqual(
'https://bugs.launchpad.dev/foo/+filebug',
Y.one('#filebug-form').get('action'));
- },
-
- add_project_selector: function() {
- var project_selector = Y.Node.create([
- '<tr>',
- ' <td>',
- ' <label for="field.product">Project:</label>',
- ' <select size="1" name="field.product" id="field.product">',
- ' <option value="foo">Foo</option>',
- ' <option value="bar">Bar</option>',
- ' </select>',
- ' </td>',
- '</tr>'
- ].join(''));
- Y.one('#search-field').insert(project_selector, 'before');
- module.setup_product_urls();
- },
-
- /**
- * The filebug form url is correctly updated when the project changes.
- */
- test_project_change_filebug_form_action: function() {
- this.add_project_selector();
- var project = Y.one(Y.DOM.byId('field.product'));
- project.set('value', 'bar');
- simulate(project, undefined, 'change');
- Y.Assert.areEqual(
- 'https://bugs.launchpad.dev/bar/+filebug',
- Y.one('#filebug-search-form').get('action'));
- },
-
- /**
- * A user first searches for duplicate bugs and there are none.
- * They can start typing in some detail. They change the project and
- * perform a new search. Their input should be retained.
- */
- test_project_change_retains_user_input_after_dups_serach: function() {
- Y.one(Y.DOM.byId('field.product')).set('value', 'foo');
- module.setup_product_urls();
- // filebug container should not initially be visible
- this.assertIsNotVisible(null, '#filebug-form-container');
- var search_text = Y.one(Y.DOM.byId('field.search'));
- search_text.set('value', 'foo');
- var search_button = Y.one(Y.DOM.byId('field.actions.search'));
- this.config.yio.io.responseText = 'No similar bug reports.';
- this.config.yio.io.doAfter = function() {
- var comment_text = Y.one(Y.DOM.byId('field.comment'));
- comment_text.set('value', 'an error occurred');
-
- this.config.yio.io.responseText = 'Bug filing details';
- var project = Y.one(Y.DOM.byId('field.product'));
- project.set('value', 'bar');
- simulate(project, undefined, 'change');
- // filebug container should be visible
- this.assertIsVisible(null, '#filebug-form-container');
-
- // Search button should day 'Check again' because we have
- // already done a search.
- var search_button = (Y.one(Y.DOM.byId('field.actions.search')));
- Y.Assert.areEqual('Check again', search_button.get('value'));
-
- this.config.yio.io.responseText = 'No similar bug reports.';
- this.config.yio.io.doAfter = function() {
- // filebug container should be visible
- this.assertIsVisible(null, '#filebug-form-container');
- // The user input should be retained
- Y.Assert.areEqual(
- 'an error occurred', comment_text.get('value'));
- Y.ArrayAssert.itemsAreEqual(
- ['https://bugs.launchpad.dev/' +
- 'foo/+filebug-show-similar?title=foo',
- 'https://bugs.launchpad.dev/' +
- 'bar/+filebug-show-similar?title=foo'],
- this.config.yio.calls);
- };
- simulate(search_button, undefined, 'click');
- this.wait();
- };
- simulate(search_button, undefined, 'click');
- this.wait();
}
}));
=== modified file 'lib/lp/bugs/stories/guided-filebug/xx-product-guided-filebug.txt'
--- lib/lp/bugs/stories/guided-filebug/xx-product-guided-filebug.txt 2012-02-23 16:15:43 +0000
+++ lib/lp/bugs/stories/guided-filebug/xx-product-guided-filebug.txt 2012-08-02 08:44:19 +0000
@@ -24,7 +24,7 @@
There is 1 error.
>>> for message in top_portlet.findAll(attrs={'class': 'message'}):
... print message.renderContents()
- A summary is required.
+ Required input is missing.
The user fills in some keywords, and clicks a button to search existing
bugs.
=== modified file 'lib/lp/bugs/stories/guided-filebug/xx-project-guided-filebug.txt'
--- lib/lp/bugs/stories/guided-filebug/xx-project-guided-filebug.txt 2012-02-23 16:15:43 +0000
+++ lib/lp/bugs/stories/guided-filebug/xx-project-guided-filebug.txt 2012-08-02 08:44:19 +0000
@@ -16,14 +16,16 @@
>>> user_browser.getControl('Project', index=0).options
['evolution']
-After we selected a product and entered a summary, we get presented with
-a list of possible duplicates.
+After we selected a product and entered a summary, we're sent to the
+product's +filebug page and presented with a list of possible duplicates.
>>> user_browser.getControl('Project', index=0).value = ['evolution']
>>> user_browser.getControl('Summary', index=0).value = (
... 'Evolution crashes')
>>> user_browser.getControl('Continue').click()
+ >>> user_browser.url
+ 'http://bugs.launchpad.dev/evolution/+filebug?field.actions.search=Continue&field.title=Evolution+crashes&field.tags='
>>> print find_main_content(user_browser.contents).renderContents()
<...
No similar bug reports were found...
@@ -40,78 +42,6 @@
'Bug #...Evolution crashes... : Bugs : Evolution'
-Subscribing to a similar bug
-----------------------------
-
-If our bug is described by one of the suggested similar bugs, we can
-subscribe to it instead of filing a new bug. This also loosely implies a
-"me too" vote.
-
- >>> user_browser.open("http://bugs.launchpad.dev/gnome/+filebug")
- >>> user_browser.getControl('Project', index=0).value = ['evolution']
- >>> user_browser.getControl('Summary', index=0).value = (
- ... 'Evolution crashes')
- >>> user_browser.getControl('Continue').click()
-
-As before, we get a list of similar bugs to choose from, including the
-bugs we filed recently.
-
- >>> from lp.bugs.tests.bug import print_bugs_list
- >>> print_bugs_list(user_browser.contents, "similar-bugs")
- #... Evolution crashes
- New (0 comments) last updated ...
-
-This one matches, so we subscribe.
-
- >>> user_browser.getControl(
- ... "Yes, this is the bug I'm trying to report").click()
-
- >>> print user_browser.url
- http://bugs.launchpad.dev/evolution/+bug/...
-
-But, of course, we're already subscribed because we created it.
-
- >>> for message in get_feedback_messages(user_browser.contents):
- ... print message
- This bug is already marked as affecting you.
-
-
-Filing a bug when there are none similar
-----------------------------------------
-
-When no similar bugs are found the form works the same but appears
-different in the user agent.
-
- >>> user_browser.open("http://launchpad.dev/gnome/+filebug")
-
-Submitting some distinctive details...
-
- >>> user_browser.getControl('Project', index=0).value = ['evolution']
- >>> user_browser.getControl('Summary', index=0).value = (
- ... 'Faznambutron dumps core unless clenching')
- >>> user_browser.getControl('Continue').click()
-
-...yields no similar bugs. In fact, the similar bugs table is not even
-shown.
-
- >>> similar_bugs_list = find_tag_by_id(
- ... user_browser.contents, "similar-bugs")
- >>> print similar_bugs_list
- None
-
-But, as before, entering a description and submitting the bug takes the
-user to the bug page.
-
- >>> user_browser.getControl('Further information').value = (
- ... 'Faznambutron is a plugin designed to ...')
- >>> user_browser.getControl('Submit Bug Report').click()
- >>> user_browser.url
- 'http://bugs.launchpad.dev/evolution/+bug/...'
-
- >>> user_browser.title
- 'Bug #...Faznambutron dumps core... : Bugs : Evolution'
-
-
Empty ProjectGroups
-------------------
=== modified file 'lib/lp/bugs/templates/bugtarget-filebug-search.pt'
--- lib/lp/bugs/templates/bugtarget-filebug-search.pt 2012-07-07 14:00:30 +0000
+++ lib/lp/bugs/templates/bugtarget-filebug-search.pt 2012-08-02 08:44:19 +0000
@@ -57,12 +57,6 @@
<metal:widget metal:use-macro="context/@@launchpad_form/widget_row" />
</tal:product_widget>
- <tal:bugtarget
- tal:define="widget nocall:view/widgets/bugtarget|nothing"
- tal:condition="widget">
- <metal:widget metal:use-macro="context/@@launchpad_form/widget_row" />
- </tal:bugtarget>
-
<tal:hidden_tags tal:replace="structure view/widgets/tags/hidden" />
<tr>
@@ -137,7 +131,7 @@
</tal:filebug-form>
</div>
</tal:not_project_group>
- <p class="hidden">
+ <p class="hidden" tal:condition="view/inline_filebug_base_url|nothing">
<a id="filebug-base-url"
tal:attributes="href view/inline_filebug_base_url"></a>
<a id="filebug-form-url"
=== modified file 'lib/lp/bugs/templates/bugtarget-macros-filebug.pt'
--- lib/lp/bugs/templates/bugtarget-macros-filebug.pt 2012-07-31 03:14:11 +0000
+++ lib/lp/bugs/templates/bugtarget-macros-filebug.pt 2012-08-02 08:44:19 +0000
@@ -4,12 +4,6 @@
omit-tag="">
<metal:basic_filebug_widgets define-macro="basic_filebug_widgets">
- <tal:bugtarget
- tal:define="widget nocall:view/widgets/bugtarget|nothing"
- tal:condition="widget">
- <metal:widget use-macro="context/@@launchpad_form/widget_row" />
- </tal:bugtarget>
-
<tr tal:condition="view/widgets/packagename|nothing">
<th colspan="2" style="text-align: left"><label
tal:attributes="for view/widgets/packagename/name"
@@ -154,10 +148,6 @@
Change this <span class="sprite edit action-icon">Edit</span>
</a>
</div>
- <span tal:condition="view/frontpage_form">
- You can <a href="+filebug">refine and resubmit</a> your bug
- report.
- </span>
<tal:upstream condition="view/contextIsProduct">
<tal:defines define="bugtracker product_or_distro/getExternalBugTracker">
<h3>
Follow ups