Merge lp:~edwin-grubbs/launchpad/bug-35728-bugtracker-overlay into lp:launchpad

Proposed by Edwin Grubbs
Status: Merged
Approved by: Aaron Bentley
Approved revision: no longer in the source branch.
Merged at revision: 11051
Proposed branch: lp:~edwin-grubbs/launchpad/bug-35728-bugtracker-overlay
Merge into: lp:launchpad
Diff against target: 554 lines (+325/-19)
13 files modified
lib/canonical/launchpad/icing/style-3-0.css.in (+14/-0)
lib/canonical/launchpad/webapp/launchpadform.py (+6/-1)
lib/canonical/widgets/popup.py (+50/-0)
lib/canonical/widgets/product.py (+4/-4)
lib/lp/app/templates/base-layout-macros.pt (+2/-0)
lib/lp/bugs/browser/bugtracker.py (+2/-2)
lib/lp/bugs/interfaces/bugtracker.py (+3/-2)
lib/lp/bugs/javascript/bugtracker_overlay.js (+131/-0)
lib/lp/bugs/stories/bugtracker/xx-bugtracker.txt (+8/-4)
lib/lp/registry/javascript/milestoneoverlay.js (+2/-2)
lib/lp/registry/windmill/tests/test_add_bugtracker.py (+100/-0)
lib/lp/registry/windmill/tests/test_add_milestone.py (+2/-4)
utilities/lp-deps.py (+1/-0)
To merge this branch: bzr merge lp:~edwin-grubbs/launchpad/bug-35728-bugtracker-overlay
Reviewer Review Type Date Requested Status
Curtis Hovey (community) ui Approve
Aaron Bentley (community) Approve
Review via email: mp+28100@code.launchpad.net

Commit message

Add form overlay for creating a new bug tracker to the $project/+configure-bugtracker page.

Description of the change

Summary
-------

Turned /bugs/bugtrackers/+newbugtracker into a form overlay to be
used on the $project/+configure-bugtracker page.

Implementation details
----------------------

The ProductBugTrackerWidget now uses the BugTrackerPickerWidget as one
of its subwidgets.
    lib/canonical/widgets/product.py
    lib/canonical/widgets/popup.py
    lib/lp/bugs/javascript/bugtracker_overlay.js
    lib/lp/registry/windmill/tests/test_add_bugtracker.py
    lib/lp/app/templates/base-layout-macros.pt
    utilities/lp-deps.py

Re-ordered the field names so that the required fields are at the top. I
also put the bug tracker type select-menu at the very top, since it
makes it very clear as to what this form is all about.
    lib/lp/bugs/browser/bugtracker.py

Minor fixes.
    lib/canonical/launchpad/icing/style-3-0.css.in
    lib/canonical/launchpad/webapp/launchpadform.py
    lib/lp/bugs/interfaces/bugtracker.py

Prevent the link that displays the form overlay from following the link
when an error interrupts the event handler, since it makes hard to
figure out what the error is when you immediately jump to another page.
    lib/lp/registry/javascript/milestoneoverlay.js
    lib/lp/registry/windmill/tests/test_add_milestone.py

Tests
-----

./bin/test -vv --layer=RegistryWindmillLayer \
    -t test_add_bugtracker -t test_add_milestone

Demo and Q/A
------------

* Open http://launchpad.dev/bazaar/+configure-bugtracker
  * Click on "Register an external bug tracker"
  * Enter name, title, and location.
  * Submit form.
  * The +configure-bugtracker form should now have the
    name of the newly created bug tracker entered, and
    the radio button should be selected.

To post a comment you must log in.
Revision history for this message
Aaron Bentley (abentley) wrote :

Please stop manually creating a unique string for the bugtracker_name. Other than that, this looks fine.

review: Approve
Revision history for this message
Curtis Hovey (sinzui) wrote :

The UI looks good and behaves well in Firefox.

It behaves oddly in Epiphany (Webkit) and I suspect there is a deeper issue than your branch at play. I can use the overlay with my mouse once. The Choose and Register links do not work (no hover, no click). I cannot correct a mistake using my mouse. I can use the keyboard.

This is still vast improvement over what can do, so I think this is good to land, but report a bug so that we can follow up on this.

review: Approve (ui)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/canonical/launchpad/icing/style-3-0.css.in'
--- lib/canonical/launchpad/icing/style-3-0.css.in 2010-06-17 00:39:03 +0000
+++ lib/canonical/launchpad/icing/style-3-0.css.in 2010-06-23 23:09:29 +0000
@@ -126,6 +126,20 @@
126 Universal presentation126 Universal presentation
127 Block elements.127 Block elements.
128*/128*/
129/* XXX EdwinGrubbs 2010-06-18 bug=570354
130 * The PrettyOverlay css uses static values for the width, but
131 * the overlay needs to stretch for forms with wide input fields.
132 */
133.yui-pretty-overlay {
134 width: auto !important;
135 min-width: 402px;
136 }
137
138.yui-pretty-overlay #yui-pretty-overlay-modal {
139 width: auto !important;
140 min-width: 340px;
141 }
142
129html, body {143html, body {
130 font-family: "dejavu sans", "bitstream vera sans", verdana, sans-serif;144 font-family: "dejavu sans", "bitstream vera sans", verdana, sans-serif;
131 font-size: 93%;145 font-size: 93%;
132146
=== renamed directory 'lib/lp/bugs/javascript' => 'lib/canonical/launchpad/javascript/bugs'
=== modified file 'lib/canonical/launchpad/webapp/launchpadform.py'
--- lib/canonical/launchpad/webapp/launchpadform.py 2010-03-15 16:58:49 +0000
+++ lib/canonical/launchpad/webapp/launchpadform.py 2010-06-23 23:09:29 +0000
@@ -16,6 +16,7 @@
16 ]16 ]
1717
18import transaction18import transaction
19
19from zope.interface import classImplements, providedBy20from zope.interface import classImplements, providedBy
20from zope.interface.advice import addClassAdvisor21from zope.interface.advice import addClassAdvisor
21from zope.event import notify22from zope.event import notify
@@ -243,7 +244,7 @@
243 self.errors.append(cleanmsg)244 self.errors.append(cleanmsg)
244245
245 @staticmethod246 @staticmethod
246 def validate_none(self, action, data):247 def validate_none(form, action, data):
247 """Do not do any validation.248 """Do not do any validation.
248249
249 This is to be used in subclasses that have actions in which no250 This is to be used in subclasses that have actions in which no
@@ -473,6 +474,10 @@
473 if referrer is None:474 if referrer is None:
474 # "referer" is misspelled in the HTTP specification.475 # "referer" is misspelled in the HTTP specification.
475 referrer = self.request.getHeader('referer')476 referrer = self.request.getHeader('referer')
477 # Windmill doesn't pass in a correct referer.
478 if (referrer is not None
479 and '/windmill-serv/remote.html' in referrer):
480 referrer = None
476 else:481 else:
477 attribute_name = self.request.form.get('_return_attribute_name')482 attribute_name = self.request.form.get('_return_attribute_name')
478 attribute_value = self.request.form.get('_return_attribute_value')483 attribute_value = self.request.form.get('_return_attribute_value')
479484
=== modified file 'lib/canonical/widgets/popup.py'
--- lib/canonical/widgets/popup.py 2010-01-29 10:52:58 +0000
+++ lib/canonical/widgets/popup.py 2010-06-23 23:09:29 +0000
@@ -180,6 +180,56 @@
180 return '/people/'180 return '/people/'
181181
182182
183class BugTrackerPickerWidget(VocabularyPickerWidget):
184 link_template = """
185 or (<a id="%(activator_id)s" href="/bugs/bugtrackers/+newbugtracker"
186 >Register an external bug tracker&hellip;</a>)
187 <script>
188 LPS.use('lp.bugs.bugtracker_overlay', function(Y) {
189 if (Y.UA.ie) {
190 return;
191 }
192 Y.on('domready', function () {
193 // After the success handler finishes, it calls the
194 // next_step function.
195 var next_step = function(bug_tracker) {
196 // Fill in the text field with either the name of
197 // the newly created bug tracker or the name of an
198 // existing bug tracker whose base_url matches.
199 var bugtracker_text_box = Y.one(
200 Y.DOM.byId('field.bugtracker.bugtracker'));
201 if (bugtracker_text_box !== null) {
202 bugtracker_text_box.set(
203 'value', bug_tracker.get('name'));
204 // It doesn't appear possible to use onChange
205 // event, so the onKeyPress event is explicitely
206 // fired here.
207 if (bugtracker_text_box.get('onkeypress')) {
208 bugtracker_text_box.get('onkeypress')();
209 }
210 bugtracker_text_box.scrollIntoView();
211 }
212 }
213 Y.lp.bugs.bugtracker_overlay.attach_widget({
214 activate_node: Y.get('#%(activator_id)s'),
215 next_step: next_step
216 });
217 });
218 });
219 </script>
220 """
221
222 def chooseLink(self):
223 link = super(BugTrackerPickerWidget, self).chooseLink()
224 link += self.link_template % dict(
225 activator_id='create-bugtracker-link')
226 return link
227
228 @property
229 def nonajax_uri(self):
230 return '/bugs/bugtrackers/'
231
232
183class SearchForUpstreamPopupWidget(VocabularyPickerWidget):233class SearchForUpstreamPopupWidget(VocabularyPickerWidget):
184 """A SinglePopupWidget with a custom error message.234 """A SinglePopupWidget with a custom error message.
185235
186236
=== modified file 'lib/canonical/widgets/product.py'
--- lib/canonical/widgets/product.py 2010-06-16 16:56:58 +0000
+++ lib/canonical/widgets/product.py 2010-06-23 23:09:29 +0000
@@ -37,7 +37,7 @@
37from canonical.launchpad.webapp import canonical_url37from canonical.launchpad.webapp import canonical_url
38from canonical.widgets.itemswidgets import (38from canonical.widgets.itemswidgets import (
39 CheckBoxMatrixWidget, LaunchpadRadioWidget)39 CheckBoxMatrixWidget, LaunchpadRadioWidget)
40from canonical.widgets.popup import VocabularyPickerWidget40from canonical.widgets.popup import BugTrackerPickerWidget
41from canonical.widgets.textwidgets import (41from canonical.widgets.textwidgets import (
42 LowerCaseTextWidget, StrippedTextWidget)42 LowerCaseTextWidget, StrippedTextWidget)
43from lp.registry.interfaces.product import IProduct43from lp.registry.interfaces.product import IProduct
@@ -57,7 +57,7 @@
57 self.bugtracker = Choice(57 self.bugtracker = Choice(
58 vocabulary="WebBugTracker",58 vocabulary="WebBugTracker",
59 __name__='bugtracker')59 __name__='bugtracker')
60 self.bugtracker_widget = CustomWidgetFactory(VocabularyPickerWidget)60 self.bugtracker_widget = CustomWidgetFactory(BugTrackerPickerWidget)
61 setUpWidget(61 setUpWidget(
62 self, 'bugtracker', self.bugtracker, IInputWidget,62 self, 'bugtracker', self.bugtracker, IInputWidget,
63 prefix=self.name, value=field.context.bugtracker,63 prefix=self.name, value=field.context.bugtracker,
@@ -82,7 +82,7 @@
82 if self.upstream_email_address_widget.extra is None:82 if self.upstream_email_address_widget.extra is None:
83 self.upstream_email_address_widget.extra = ''83 self.upstream_email_address_widget.extra = ''
84 self.upstream_email_address_widget.extra += (84 self.upstream_email_address_widget.extra += (
85 ' onkeypress="selectWidget(\'%s.3\', event);"' % self.name)85 ''' onkeypress="selectWidget('%s.3', event);"\n''' % self.name)
8686
87 def _renderItem(self, index, text, value, name, cssClass, checked=False):87 def _renderItem(self, index, text, value, name, cssClass, checked=False):
88 # This form has a custom need to render their labels separately,88 # This form has a custom need to render their labels separately,
@@ -192,7 +192,7 @@
192 self.upstream_email_address_widget.setRenderedValue(192 self.upstream_email_address_widget.setRenderedValue(
193 value.baseurl.lstrip('mailto:'))193 value.baseurl.lstrip('mailto:'))
194 external_bugtracker_email_text = "%s %s" % (194 external_bugtracker_email_text = "%s %s" % (
195 self._renderLabel("By emailing an upstream bug contact:", 3),195 self._renderLabel("By emailing an upstream bug contact:\n", 3),
196 self.upstream_email_address_widget())196 self.upstream_email_address_widget())
197 external_bugtracker_email_arguments = dict(197 external_bugtracker_email_arguments = dict(
198 index=3, text=external_bugtracker_email_text,198 index=3, text=external_bugtracker_email_text,
199199
=== modified file 'lib/lp/app/templates/base-layout-macros.pt'
--- lib/lp/app/templates/base-layout-macros.pt 2010-06-17 19:25:53 +0000
+++ lib/lp/app/templates/base-layout-macros.pt 2010-06-23 23:09:29 +0000
@@ -181,6 +181,8 @@
181 <script type="text/javascript"181 <script type="text/javascript"
182 tal:attributes="src string:${lp_js}/lp/mapping.js"></script>182 tal:attributes="src string:${lp_js}/lp/mapping.js"></script>
183 <script type="text/javascript"183 <script type="text/javascript"
184 tal:attributes="src string:${lp_js}/bugs/bugtracker_overlay.js"></script>
185 <script type="text/javascript"
184 tal:attributes="src string:${lp_js}/registry/milestoneoverlay.js"></script>186 tal:attributes="src string:${lp_js}/registry/milestoneoverlay.js"></script>
185 <script type="text/javascript"187 <script type="text/javascript"
186 tal:attributes="src string:${lp_js}/registry/milestonetable.js"></script>188 tal:attributes="src string:${lp_js}/registry/milestonetable.js"></script>
187189
=== modified file 'lib/lp/bugs/browser/bugtracker.py'
--- lib/lp/bugs/browser/bugtracker.py 2009-09-04 08:17:15 +0000
+++ lib/lp/bugs/browser/bugtracker.py 2010-06-23 23:09:29 +0000
@@ -82,8 +82,8 @@
82 page_title = u"Register an external bug tracker"82 page_title = u"Register an external bug tracker"
83 schema = IBugTracker83 schema = IBugTracker
84 label = page_title84 label = page_title
85 field_names = ['name', 'bugtrackertype', 'title', 'summary',85 field_names = ['bugtrackertype', 'name', 'title', 'baseurl', 'summary',
86 'baseurl', 'contactdetails']86 'contactdetails']
8787
88 def setUpWidgets(self, context=None):88 def setUpWidgets(self, context=None):
89 # We only show those bug tracker types for which there can be89 # We only show those bug tracker types for which there can be
9090
=== modified file 'lib/lp/bugs/interfaces/bugtracker.py'
--- lib/lp/bugs/interfaces/bugtracker.py 2010-04-15 08:45:31 +0000
+++ lib/lp/bugs/interfaces/bugtracker.py 2010-06-23 23:09:29 +0000
@@ -68,7 +68,8 @@
68 bugtracker = getUtility(IBugTrackerSet).queryByBaseURL(input)68 bugtracker = getUtility(IBugTrackerSet).queryByBaseURL(input)
69 if bugtracker is not None and bugtracker != self.context:69 if bugtracker is not None and bugtracker != self.context:
70 raise LaunchpadValidationError(70 raise LaunchpadValidationError(
71 "%s is already registered in Launchpad." % input)71 '%s is already registered in Launchpad as "%s" (%s).'
72 % (input, bugtracker.title, bugtracker.name))
7273
7374
74class BugTrackerType(DBEnumeratedType):75class BugTrackerType(DBEnumeratedType):
@@ -183,7 +184,7 @@
183 BugTrackerNameField(184 BugTrackerNameField(
184 title=_('Name'),185 title=_('Name'),
185 constraint=name_validator,186 constraint=name_validator,
186 description=_('An URL-friendly name for the bug tracker, '187 description=_('A URL-friendly name for the bug tracker, '
187 'such as "mozilla-bugs".')))188 'such as "mozilla-bugs".')))
188 title = exported(189 title = exported(
189 TextLine(190 TextLine(
190191
=== added directory 'lib/lp/bugs/javascript'
=== added file 'lib/lp/bugs/javascript/bugtracker_overlay.js'
--- lib/lp/bugs/javascript/bugtracker_overlay.js 1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/javascript/bugtracker_overlay.js 2010-06-23 23:09:29 +0000
@@ -0,0 +1,131 @@
1/* Copyright 2010 Canonical Ltd. This software is licensed under the
2 * GNU Affero General Public License version 3 (see the file LICENSE).
3 *
4 * A bugtracker form overlay that can create a bugtracker within any page.
5 *
6 * @namespace Y.lp.bugs.bugtracker_overlay
7 * @requires dom, node, io-base, lazr.anim, lazr.formoverlay
8 */
9YUI.add('lp.bugs.bugtracker_overlay', function(Y) {
10 Y.log('loading lp.bugs.bugtracker_overlay');
11 var namespace = Y.namespace('lp.bugs.bugtracker_overlay');
12
13 var bugtracker_form;
14 var next_step;
15
16 var save_new_bugtracker = function(data) {
17
18 var parameters = {
19 bug_tracker_type: data['field.bugtrackertype'][0],
20 name: data['field.name'][0].toLowerCase(),
21 title: data['field.title'][0],
22 base_url: data['field.baseurl'][0],
23 summary: data['field.summary'][0],
24 contact_details: data['field.contactdetails'][0]
25 };
26
27 var finish_new_bugtracker = function(entry) {
28 bugtracker_form.clearError();
29 bugtracker_form.hide();
30 // Reset the HTML form inside the widget.
31 bugtracker_form.get('contentBox').one('form').reset();
32 next_step(entry);
33 };
34
35 var client = new LP.client.Launchpad();
36 client.named_post('/bugs/bugtrackers', 'ensureBugTracker', {
37 parameters: parameters,
38 on: {
39 success: finish_new_bugtracker,
40 failure: function (ignore, response, args) {
41 var error_box = Y.one('#bugtracker-error');
42 var error_message = response.statusText + '\n\n' +
43 response.responseText;
44 bugtracker_form.showError(error_message);
45 // XXX EdwinGrubbs 2007-06-18 bug=596025
46 // This should be done by FormOverlay.showError().
47 bugtracker_form.error_node.scrollIntoView();
48 }
49 }
50 });
51 };
52
53
54 var setup_bugtracker_form = function () {
55 var form_submit_button = Y.Node.create(
56 '<input type="submit" name="field.actions.register" ' +
57 'id="formoverlay-add-bugtracker" value="Create bug tracker"/>');
58 bugtracker_form = new Y.lazr.FormOverlay({
59 headerContent: '<h2>Create Bug Tracker</h2>',
60 form_submit_button: form_submit_button,
61 centered: true,
62 form_submit_callback: save_new_bugtracker,
63 visible: false
64 });
65 bugtracker_form.loadFormContentAndRender(
66 '/bugs/bugtrackers/+newbugtracker/++form++');
67 // XXX EdwinGrubbs 2010-06-18 bug=596130
68 // render() and show() will actually be called before the
69 // asynchronous io call finishes, so the widget appears first
70 // without any content. However, this is better than loading the
71 // form every time the page loads despite the form overlay being
72 // used rarely.
73 bugtracker_form.render();
74 bugtracker_form.show();
75 };
76
77 var show_bugtracker_form = function(e) {
78 e.preventDefault();
79 if (bugtracker_form) {
80 bugtracker_form.show();
81 } else {
82 // This function call is asynchronous, so we can move
83 // bugtracker_form.show() below it.
84 setup_bugtracker_form();
85 }
86
87 // XXX EdwinGrubbs 2010-06-18 bug=596113
88 // FormOverlay calls centered(), which can cause this tall form
89 // to be position where the top of the form is no longer
90 // accessible.
91 var bounding_box = bugtracker_form.get('boundingBox');
92 var min_top = 10;
93 if (bounding_box.get('offsetTop') < min_top) {
94 bounding_box.setStyle('top', min_top + 'px');
95 }
96 };
97
98 /**
99 * Attaches a bugtracker form overlay widget to an element.
100 *
101 * @method attach_widget
102 * @param {Object} config Object literal of config name/value pairs.
103 * activate_node is the node that shows the form
104 * when it is clicked.
105 * next_step is the function to be called after
106 * the bugtracker is created.
107 */
108 namespace.attach_widget = function(config) {
109 Y.log('lp.bugs.bugtracker_overlay.attach_widget()');
110 if (Y.UA.ie) {
111 return;
112 }
113 if (config === undefined) {
114 throw new Error(
115 "Missing attach_widget config for bugtracker_overlay.");
116 }
117 if (config.activate_node === undefined ||
118 config.next_step === undefined) {
119 throw new Error(
120 "attach_widget config for bugtracker_overlay has " +
121 "undefined properties.");
122 }
123 next_step = config.next_step;
124 Y.log('lp.bugs.bugtracker_overlay.attach_widget() setup onclick');
125 config.activate_node.addClass('js-action');
126 config.activate_node.on('click', show_bugtracker_form);
127 };
128
129}, "0.1", {"requires": [
130 "dom", "node", "io-base", "lazr.anim", "lazr.formoverlay", "lp.calendar"
131 ]});
0132
=== added directory 'lib/lp/bugs/javascript/tests'
=== modified file 'lib/lp/bugs/stories/bugtracker/xx-bugtracker.txt'
--- lib/lp/bugs/stories/bugtracker/xx-bugtracker.txt 2010-06-16 15:56:08 +0000
+++ lib/lp/bugs/stories/bugtracker/xx-bugtracker.txt 2010-06-23 23:09:29 +0000
@@ -72,7 +72,8 @@
72 >>> for message in find_tags_by_class(user_browser.contents, 'message'):72 >>> for message in find_tags_by_class(user_browser.contents, 'message'):
73 ... print extract_text(message)73 ... print extract_text(message)
74 There is 1 error.74 There is 1 error.
75 http://bugzilla.mozilla.org/ is already registered in Launchpad.75 http://bugzilla.mozilla.org/ is already registered in Launchpad
76 as "The Mozilla.org Bug Tracker" (mozilla.org).
7677
77The same happens if the requested URL is aliased to another bug78The same happens if the requested URL is aliased to another bug
78tracker. Aliases can be edited once a bug tracker has been added, but79tracker. Aliases can be edited once a bug tracker has been added, but
@@ -94,7 +95,8 @@
94 >>> for message in find_tags_by_class(user_browser.contents, 'message'):95 >>> for message in find_tags_by_class(user_browser.contents, 'message'):
95 ... print extract_text(message)96 ... print extract_text(message)
96 There is 1 error.97 There is 1 error.
97 http://alias.example.com/ is already registered in Launchpad.98 http://alias.example.com/ is already registered in Launchpad
99 as "GnomeGBug GTracker" (gnome-bugzilla).
98100
99After successfully registering the bug tracker, the user is redirected101After successfully registering the bug tracker, the user is redirected
100to the bug tracker page.102to the bug tracker page.
@@ -201,7 +203,8 @@
201 >>> for message in get_feedback_messages(user_browser.contents):203 >>> for message in get_feedback_messages(user_browser.contents):
202 ... print message204 ... print message
203 There is 1 error.205 There is 1 error.
204 http://bugzilla.mozilla.org/ is already registered in Launchpad.206 http://bugzilla.mozilla.org/ is already registered in Launchpad
207 as "The Mozilla.org Bug Tracker" (mozilla.org).
205208
206If the user inadvertently enters an invalid URL, they are shown an209If the user inadvertently enters an invalid URL, they are shown an
207informative error message explaining why it is invalid.210informative error message explaining why it is invalid.
@@ -304,7 +307,8 @@
304 >>> for message in get_feedback_messages(user_browser.contents):307 >>> for message in get_feedback_messages(user_browser.contents):
305 ... print message308 ... print message
306 There is 1 error.309 There is 1 error.
307 http://bugzilla.mozilla.org/ is already registered in Launchpad.310 http://bugzilla.mozilla.org/ is already registered in Launchpad
311 as "The Mozilla.org Bug Tracker" (mozilla.org).
308312
309Multiple aliases can be entered by separating URLs with whitespace.313Multiple aliases can be entered by separating URLs with whitespace.
310314
311315
=== modified file 'lib/lp/registry/javascript/milestoneoverlay.js'
--- lib/lp/registry/javascript/milestoneoverlay.js 2010-04-29 15:21:05 +0000
+++ lib/lp/registry/javascript/milestoneoverlay.js 2010-06-23 23:09:29 +0000
@@ -71,7 +71,8 @@
71 milestone_form.show();71 milestone_form.show();
72 };72 };
7373
74 show_milestone_form = function(e) {74 var show_milestone_form = function(e) {
75 e.preventDefault();
75 if (milestone_form) {76 if (milestone_form) {
76 milestone_form.show();77 milestone_form.show();
77 } else {78 } else {
@@ -79,7 +80,6 @@
79 // milestone_form.show() below it.80 // milestone_form.show() below it.
80 setup_milestone_form();81 setup_milestone_form();
81 }82 }
82 e.preventDefault();
83 };83 };
8484
85 /**85 /**
8686
=== added file 'lib/lp/registry/windmill/tests/test_add_bugtracker.py'
--- lib/lp/registry/windmill/tests/test_add_bugtracker.py 1970-01-01 00:00:00 +0000
+++ lib/lp/registry/windmill/tests/test_add_bugtracker.py 2010-06-23 23:09:29 +0000
@@ -0,0 +1,100 @@
1# Copyright 2009 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""Test adding bug tracker in formoverlay."""
5
6__metaclass__ = type
7__all__ = []
8
9import unittest
10
11from canonical.launchpad.windmill.testing import lpuser
12
13from lp.registry.windmill.testing import RegistryWindmillLayer
14from lp.testing import WindmillTestCase
15
16
17def test_inline_add_bugtracker(client, url, name=None, suite='bugtracker',
18 user=lpuser.FOO_BAR):
19 """Test the form overlay for adding a bugtracker.
20
21 :param name: Name of the test.
22 :param url: Starting url.
23 :param suite: The suite in which this test is part of.
24 :param user: The user who should be logged in.
25 """
26 bugtracker_name = u'FOObar'
27 title = u'\xdf-title-%s' % bugtracker_name
28 location = u'http://example.com/%s' % bugtracker_name
29
30 user.ensure_login(client)
31 client.open(url=url)
32 client.waits.forPageLoad(timeout=u'20000')
33
34 client.waits.forElement(id=u'create-bugtracker-link')
35
36 # Click the "Create external bug tracker" link.
37 client.click(id=u'create-bugtracker-link')
38
39 # Submit bugtracker form.
40 client.waits.forElement(id=u'field.name')
41 client.type(id='field.name', text=bugtracker_name)
42 client.type(id='field.title', text=title)
43 client.type(id='field.baseurl', text=location)
44 client.click(id=u'formoverlay-add-bugtracker')
45
46 # Verify that the bugtracker name was entered in the text box.
47 client.waits.sleep(milliseconds='1000')
48 client.asserts.assertProperty(
49 id="field.bugtracker.bugtracker",
50 validator='value|%s' % bugtracker_name.lower())
51 client.asserts.assertChecked(id="field.bugtracker.2")
52
53 # Verify error message when trying to create a bugtracker with a
54 # conflicting name.
55 client.click(id=u'create-bugtracker-link')
56 client.waits.forElement(id=u'field.name')
57 client.type(id='field.name', text=bugtracker_name)
58 client.click(id=u'formoverlay-add-bugtracker')
59 client.waits.forElement(
60 xpath="//div[contains(@class, 'yui-lazr-formoverlay-errors')]/ul/li")
61 client.asserts.assertTextIn(
62 classname='yui-lazr-formoverlay-errors',
63 validator='name: %s is already in use' % bugtracker_name.lower())
64 client.click(classname='close-button')
65
66 # Configure bug tracker for the project.
67 client.click(id=u'field.actions.change')
68
69 # You should now be on the project index page.
70 client.waits.forElement(
71 xpath="//a[contains(@class, 'menu-link-configure_bugtracker')]")
72 client.click(
73 xpath="//a[contains(@class, 'menu-link-configure_bugtracker')]")
74
75 # Verify that the new bug tracker was configured for this project.
76 client.waits.forElement(id="field.bugtracker.bugtracker")
77 client.asserts.assertProperty(
78 id="field.bugtracker.bugtracker",
79 validator='value|%s' % bugtracker_name.lower())
80 client.asserts.assertChecked(id="field.bugtracker.2")
81
82
83class TestAddBugTracker(WindmillTestCase):
84 """Test form overlay widget for adding a bug tracker."""
85
86 # This test doesn't run well in the BugsWindmillLayer, since
87 # submitting the +configure-bugtracker form takes you back to
88 # the project index page, which is not on the bugs.launchpad.dev.
89 layer = RegistryWindmillLayer
90 suite_name = 'AddBugTracker'
91
92 def test_adding_bugtracker_for_project(self):
93 test_inline_add_bugtracker(
94 self.client,
95 url='http://launchpad.dev:8085/bzr/+configure-bugtracker',
96 name='test_inline_add_bugtracker_for_project')
97
98
99def test_suite():
100 return unittest.TestLoader().loadTestsFromName(__name__)
0101
=== modified file 'lib/lp/registry/windmill/tests/test_add_milestone.py'
--- lib/lp/registry/windmill/tests/test_add_milestone.py 2010-02-01 18:37:00 +0000
+++ lib/lp/registry/windmill/tests/test_add_milestone.py 2010-06-23 23:09:29 +0000
@@ -1,7 +1,7 @@
1# Copyright 2009 Canonical Ltd. This software is licensed under the1# Copyright 2009 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Test for translation import queue behaviour."""4"""Test adding milestone in formoverlay."""
55
6__metaclass__ = type6__metaclass__ = type
7__all__ = []7__all__ = []
@@ -24,9 +24,7 @@
24 :param suite: The suite in which this test is part of.24 :param suite: The suite in which this test is part of.
25 :param user: The user who should be logged in.25 :param user: The user who should be logged in.
26 """26 """
27 # Ensure that the milestone name doesn't conflict with previous27 milestone_name = u'FOObar'
28 # test runs, and test that it correctly lowercases the name.
29 milestone_name = u'FOObar%x' % int(time.time())
30 code_name = u'code-%s' % milestone_name28 code_name = u'code-%s' % milestone_name
3129
32 user.ensure_login(client)30 user.ensure_login(client)
3331
=== modified file 'utilities/lp-deps.py'
--- utilities/lp-deps.py 2010-06-14 22:18:14 +0000
+++ utilities/lp-deps.py 2010-06-23 23:09:29 +0000
@@ -20,6 +20,7 @@
20# JS_DIRSET is a tuple of the dir where the code exists, and the name of the20# JS_DIRSET is a tuple of the dir where the code exists, and the name of the
21# symlink it should be linked as in the icing build directory.21# symlink it should be linked as in the icing build directory.
22JS_DIRSET = [22JS_DIRSET = [
23 (os.path.join('lib', 'lp', 'bugs', 'javascript'), 'bugs'),
23 (os.path.join('lib', 'lp', 'code', 'javascript'), 'code'),24 (os.path.join('lib', 'lp', 'code', 'javascript'), 'code'),
24 (os.path.join('lib', 'lp', 'registry', 'javascript'), 'registry'),25 (os.path.join('lib', 'lp', 'registry', 'javascript'), 'registry'),
25 (os.path.join('lib', 'lp', 'translations', 'javascript'), 'translations'),26 (os.path.join('lib', 'lp', 'translations', 'javascript'), 'translations'),