Merge lp:~thumper/launchpad/edit-commit-msg-link into lp:launchpad/db-devel

Proposed by Tim Penhey
Status: Merged
Merged at revision: not available
Proposed branch: lp:~thumper/launchpad/edit-commit-msg-link
Merge into: lp:launchpad/db-devel
Diff against target: 316 lines (+120/-27)
7 files modified
lib/canonical/launchpad/javascript/code/codereview.js (+66/-3)
lib/canonical/widgets/lazrjs.py (+7/-2)
lib/lp/app/templates/base-layout-macros.pt (+3/-1)
lib/lp/code/browser/branchmergeproposal.py (+5/-5)
lib/lp/code/stories/branches/xx-branch-merge-proposals.txt (+4/-3)
lib/lp/code/templates/branchmergeproposal-index.pt (+32/-10)
lib/lp/code/windmill/tests/test_branch_merge_proposal.py (+3/-3)
To merge this branch: bzr merge lp:~thumper/launchpad/edit-commit-msg-link
Reviewer Review Type Date Requested Status
Francis J. Lacoste (community) release-critical Approve
Māris Fogels (community) js Approve
Michael Hudson-Doyle Abstain
Martin Albisetti (community) ui Approve
Guilherme Salgado Pending
Review via email: mp+15260@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Tim Penhey (thumper) wrote :

Change the UI so it doesn't show an empty commit message in the editor, but instead shows a link.

Hooks into the editor events so it knows to flash green or red when the commit message ends up empty.

Revision history for this message
Martin Albisetti (beuno) wrote :

This looks great, Tim! Thanks for working on it :)

What do you think about moving the link closer to the information on the MP? (ie, underneath "merge into")?

review: Approve (ui)
Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote :

All the interesting stuff is Javascript, which I don't really feel competent to review :( It looks fine, but I don't know anything about our coding standards really.

I'm not sure that the block starting:

+ <div id="commit-message" class="yui-g">
+ <tal:no-commit-message condition="not: context/commit_message">

Can't be better factored, but it's TAL so maybe not.

review: Abstain
Revision history for this message
Tim Penhey (thumper) wrote :

On Fri, 27 Nov 2009 16:37:59 Michael Hudson wrote:
> Review: Abstain
> All the interesting stuff is Javascript, which I don't really feel
> competent to review :( It looks fine, but I don't know anything about our
> coding standards really.
>
> I'm not sure that the block starting:
>
> + <div id="commit-message" class="yui-g">
> + <tal:no-commit-message condition="not: context/commit_message">
>
> Can't be better factored, but it's TAL so maybe not.

No it can't really, there are several bits that follow.

  reviewer launchpad

Revision history for this message
Māris Fogels (mars) wrote :

Hi Tim,

As we discussed on IRC, your approach is good. However, I do have a question or two about how you chose to integrate the widget into Launchpad.

I'm marking this as Needs Information for now. If you have already considered and confirmed the answers, then feel free to land the code with r=mars.

First, I don't understand why you had to create your own wrapper for the multiline editor. Did the inline editor's activator widget not work? The Activator is used to make the current set of inline editors flash and spin.

Line by line:

• 13: I strongly suggest using a different namespace to store the static reference to the widget. The 'lp' namespace would be an acceptable place.
• 27: Is the message variable reliably an empty string, or could it possibly be null? Check the inline editor's message attribute getter. Does the inline editor have an isEmpty() method?
• 50: Do you want to use e.preventDefault(), or e.halt()?
• 56: Too bad you have to call a protected method to trigger the editor. That is a wart in the API.
• 89: See my above comment about using the 'lp' namespace to host the global variable instead of using Y itself.

var lpns = Y.namespace('lp');
if (!lpns.widgets) { lpns.widgets = {}; }
lpns.widgets['%s'] = widget;

Maris

review: Needs Information (js)
Revision history for this message
Tim Penhey (thumper) wrote :

On Sat, 28 Nov 2009 04:54:18 Māris Fogels wrote:
> First, I don't understand why you had to create your own wrapper for the
> multiline editor. Did the inline editor's activator widget not work? The
> Activator is used to make the current set of inline editors flash and
> spin.

I'm sorry. I don't understand this at all. What activator widget?

Do you mean this code?

> var widget = Y.lp.widgets['edit-commit-message'];
> widget.editor.on('save', function() {
> commit_message_listener(this.get('value'), true);
> });
> widget.editor.on('cancel', function() {
> commit_message_listener(this.get('value'), false);
> });

If I try to remove the ".editor" it doesn't work. So I can't just attach to
the "save" or "cancel" button of the widget - which is what I'd like to do.

> Line by line:
>
> • 13: I strongly suggest using a different namespace to store the static
> reference to the widget. The 'lp' namespace would be an acceptable place.

Done.

> • 27: Is the message variable reliably an empty string, or could it
> possibly be null? Check the inline editor's message attribute getter.
> Does the inline editor have an isEmpty() method?

The widget will never give us null, only empty strings.

Since the widget doesn't allow listening on the save or cancel events, they
had to be listened to on the ieditor - and as such the widget is not easily
available to listen to. No the inline editor does not have an isEmpty method.

> • 50: Do you want to use
> e.preventDefault(), or e.halt()?

I don't know. Halt probably, but I was copying from other code. Should we
use halt if we have handled the problem?

> • 56: Too bad you have to call a protected method to trigger the editor.
> That is a wart in the API.

Yep.

Tim

Revision history for this message
Māris Fogels (mars) wrote :

Hi Tim,

As discussed on IRC, the calls to commit_message_listener() actually flash the merge link, not the original trigger or message. I couldn't read that in the code, but it makes sense. Perhaps there is some way to make that visual feature a bit clearer.

Using e.halt() is the correct behaviour if you have handled the result. In the case of clicking on a link, you usually want to prevent others from handling a click, so e.halt() is correct.

Please try to clarify the reason for flashing code a bit, and use e.halt(). With those, you will be good to land: r=mars.

Maris

review: Approve (js)
Revision history for this message
Francis J. Lacoste (flacoste) :
review: Approve (release-critical)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/canonical/launchpad/javascript/code/codereview.js'
--- lib/canonical/launchpad/javascript/code/codereview.js 2009-11-24 09:30:01 +0000
+++ lib/canonical/launchpad/javascript/code/codereview.js 2009-11-30 23:54:16 +0000
@@ -24,9 +24,67 @@
24 link.addClass('js-action');24 link.addClass('js-action');
25 link.on('click', show_request_review_form);25 link.on('click', show_request_review_form);
26 }26 }
27 link = Y.one('.menu-link-set_commit_message');
28 if (link !== null) {
29 link.addClass('js-action');
30 link.on('click', edit_commit_message);
31 }
32 var widget = Y.lp.widgets['edit-commit-message'];
33 widget.editor.on('save', function() {
34 commit_message_listener(this.get('value'), true);
35 });
36 widget.editor.on('cancel', function() {
37 commit_message_listener(this.get('value'), false);
38 });
27};39};
2840
29/*41/*
42 * Hide the commit message editor if the value is empty.
43 *
44 * If the commit message is empty, we want to show the
45 * 'Set commit message' link again. For consistency with
46 * page updates we want to flash this link so the user can
47 * see what we are doing. If the commit message was saved
48 * and is empty, then we flash green as all is good. If the
49 * user has cancelled the edit, and the commit message is
50 * empty, then we flash the link red.
51 */
52function commit_message_listener(message, saved)
53{
54 if (message == '') {
55 // Hide the multiline editor
56 Y.one('#edit-commit-message').addClass('unseen');
57 // Show the link again
58 var link = Y.one('.menu-link-set_commit_message');
59 link.removeClass('unseen');
60 if (saved) {
61 // Flash green.
62 Y.lazr.anim.green_flash({node:link}).run();
63 }
64 else {
65 // Flash red.
66 Y.lazr.anim.red_flash({node:link}).run();
67 }
68 }
69}
70
71/*
72 * Edit the commit message.
73 *
74 * Hide the link, show the multi-line editor, and set it to edit.
75 */
76function edit_commit_message(e) {
77 // We are handling this click event.
78 e.halt();
79 // Make the edit button unseen.
80 Y.one('#edit-commit-message').removeClass('unseen');
81 // Remove the unseen class from the commit message.
82 Y.one('.menu-link-set_commit_message').addClass('unseen');
83 // Trigger the edit on the multiline editor.
84 Y.lp.widgets['edit-commit-message']._triggerEdit(e);
85}
86
87/*
30 * Show the "Request a reviewer" overlay.88 * Show the "Request a reviewer" overlay.
31 */89 */
32function show_request_review_form(e) {90function show_request_review_form(e) {
@@ -149,10 +207,15 @@
149 '<input type="checkbox" checked="checked" id="show-no"/>' +207 '<input type="checkbox" checked="checked" id="show-no"/>' +
150 '&nbsp;Show line numbers</label></li>');208 '&nbsp;Show line numbers</label></li>');
151 var ul = Y.one('#review-diff div div ul.horizontal');209 var ul = Y.one('#review-diff div div ul.horizontal');
152 ul.appendChild(ui);210 if (ul) {
211 ul.appendChild(ui);
212 }
153 },213 },
154 bindUI: function(){214 bindUI: function() {
155 Y.one('#show-no').on('click', update_nos);215 var cb = Y.one('#show-no');
216 if (cb) {
217 cb.on('click', update_nos);
218 }
156 }219 }
157});220});
158221
159222
=== modified file 'lib/canonical/widgets/lazrjs.py'
--- lib/canonical/widgets/lazrjs.py 2009-10-28 08:03:36 +0000
+++ lib/canonical/widgets/lazrjs.py 2009-11-30 23:54:16 +0000
@@ -61,7 +61,7 @@
61 # Template for the activation script.61 # Template for the activation script.
62 ACTIVATION_TEMPLATE = dedent(u"""\62 ACTIVATION_TEMPLATE = dedent(u"""\
63 <script>63 <script>
64 YUI().use('lazr.editor', 'lp.client.plugins', function (Y) {64 LPS.use('lazr.editor', 'lp.client.plugins', function (Y) {
65 var widget = new Y.EditableText({65 var widget = new Y.EditableText({
66 contentBox: '#%(id)s',66 contentBox: '#%(id)s',
67 accept_empty: %(accept_empty)s,67 accept_empty: %(accept_empty)s,
@@ -198,7 +198,7 @@
198198
199 ACTIVATION_TEMPLATE = dedent(u"""\199 ACTIVATION_TEMPLATE = dedent(u"""\
200 <script>200 <script>
201 YUI().use('lazr.editor', 'lp.client.plugins', function (Y) {201 LPS.use('lazr.editor', 'lp.client.plugins', function (Y) {
202 var widget = new Y.EditableText({202 var widget = new Y.EditableText({
203 contentBox: '#%(id)s',203 contentBox: '#%(id)s',
204 accept_empty: %(accept_empty)s,204 accept_empty: %(accept_empty)s,
@@ -215,6 +215,11 @@
215 if (!Y.UA.opera) {215 if (!Y.UA.opera) {
216 widget.render();216 widget.render();
217 }217 }
218 var lpns = Y.namespace('lp');
219 if (!lpns.widgets) {
220 lpns.widgets = {};
221 }
222 lpns.widgets['%(id)s'] = widget;
218 });223 });
219 </script>224 </script>
220 """)225 """)
221226
=== modified file 'lib/lp/app/templates/base-layout-macros.pt'
--- lib/lp/app/templates/base-layout-macros.pt 2009-11-24 09:30:01 +0000
+++ lib/lp/app/templates/base-layout-macros.pt 2009-11-30 23:54:16 +0000
@@ -222,7 +222,9 @@
222 <metal:load-lavascript use-macro="context/@@+base-layout-macros/load-javascript" />222 <metal:load-lavascript use-macro="context/@@+base-layout-macros/load-javascript" />
223223
224 <script type="text/javascript">224 <script type="text/javascript">
225 YUI().use('node', 'lp', function(Y) {225 // Define a global YUI sandbox that should be used by everyone.
226 var LPS = YUI();
227 LPS.use('node', 'lp', function(Y) {
226 Y.on('load', function(e) {228 Y.on('load', function(e) {
227 sortables_init();229 sortables_init();
228 initInlineHelp();230 initInlineHelp();
229231
=== modified file 'lib/lp/code/browser/branchmergeproposal.py'
--- lib/lp/code/browser/branchmergeproposal.py 2009-11-18 04:23:29 +0000
+++ lib/lp/code/browser/branchmergeproposal.py 2009-11-30 23:54:16 +0000
@@ -195,10 +195,10 @@
195 return Link('+edit', text, icon='edit', enabled=enabled)195 return Link('+edit', text, icon='edit', enabled=enabled)
196196
197 @enabled_with_permission('launchpad.Edit')197 @enabled_with_permission('launchpad.Edit')
198 def edit_commit_message(self):198 def set_commit_message(self):
199 text = 'Edit commit message'199 text = 'Set commit message'
200 enabled = self.context.isMergable()200 enabled = self.context.isMergable()
201 return Link('+edit-commit-message', text, icon='edit',201 return Link('+edit-commit-message', text, icon='add',
202 enabled=enabled)202 enabled=enabled)
203203
204 @enabled_with_permission('launchpad.Edit')204 @enabled_with_permission('launchpad.Edit')
@@ -292,7 +292,7 @@
292 links = [292 links = [
293 'add_comment',293 'add_comment',
294 'dequeue',294 'dequeue',
295 'edit_commit_message',295 'set_commit_message',
296 'edit_status',296 'edit_status',
297 'enqueue',297 'enqueue',
298 'merge',298 'merge',
@@ -600,7 +600,7 @@
600 self.context,600 self.context,
601 'commit_message',601 'commit_message',
602 canonical_url(self.context, view_name='+edit-commit-message'),602 canonical_url(self.context, view_name='+edit-commit-message'),
603 id="edit-description",603 id="edit-commit-message",
604 title="Commit Message",604 title="Commit Message",
605 value=commit_message,605 value=commit_message,
606 accept_empty=True)606 accept_empty=True)
607607
=== modified file 'lib/lp/code/stories/branches/xx-branch-merge-proposals.txt'
--- lib/lp/code/stories/branches/xx-branch-merge-proposals.txt 2009-11-23 03:41:39 +0000
+++ lib/lp/code/stories/branches/xx-branch-merge-proposals.txt 2009-11-30 23:54:16 +0000
@@ -100,7 +100,7 @@
100 ... 'Add more <b>mojo</b>')100 ... 'Add more <b>mojo</b>')
101 >>> nopriv_browser.getControl('Update').click()101 >>> nopriv_browser.getControl('Update').click()
102102
103 >>> print_tag_with_id(nopriv_browser.contents, 'edit-description')103 >>> print_tag_with_id(nopriv_browser.contents, 'edit-commit-message')
104 Commit Message104 Commit Message
105 Add more &lt;b&gt;mojo&lt;/b&gt;105 Add more &lt;b&gt;mojo&lt;/b&gt;
106106
@@ -111,8 +111,9 @@
111 ... '')111 ... '')
112 >>> nopriv_browser.getControl('Update').click()112 >>> nopriv_browser.getControl('Update').click()
113113
114 >>> print_tag_with_id(nopriv_browser.contents, 'edit-description')114 >>> print_tag_with_id(nopriv_browser.contents, 'commit-message')
115 Commit Message115 Set commit message
116 ...
116117
117118
118Deleting merge proposals119Deleting merge proposals
119120
=== modified file 'lib/lp/code/templates/branchmergeproposal-index.pt'
--- lib/lp/code/templates/branchmergeproposal-index.pt 2009-11-13 03:21:35 +0000
+++ lib/lp/code/templates/branchmergeproposal-index.pt 2009-11-30 23:54:16 +0000
@@ -12,14 +12,17 @@
1212
13<metal:block fill-slot="head_epilogue">13<metal:block fill-slot="head_epilogue">
14 <style type="text/css">14 <style type="text/css">
15 .menu-link-set_commit_message {
16 margin-top: 1em;
17 }
15 #code-review-votes {18 #code-review-votes {
16 margin: 2em 0;19 margin: 1em 0;
17 }20 }
18 #edit-description {21 #commit-message, #edit-commit-message {
19 margin: 1em 0 0 0;22 margin: 1em 0 0 0;
20 }23 }
21 /* A page-specific fix for inline text are editing to line up box. */24 /* A page-specific fix for inline text are editing to line up box. */
22 #edit-description .yui-ieditor-input { top: 0; }25 #edit-commit-message .yui-ieditor-input { top: 0; }
23 </style>26 </style>
24</metal:block>27</metal:block>
2528
@@ -38,12 +41,34 @@
38</metal:side>41</metal:side>
3942
4043
41<div metal:fill-slot="main">44<div metal:fill-slot="main"
45 tal:define="menu context/menu:context">
4246
43 <div class="yui-g first">47 <div class="yui-g first">
44 <tal:summary replace="structure context/@@+pagelet-summary" />48 <tal:summary replace="structure context/@@+pagelet-summary" />
45 </div>49 </div>
4650
51 <div id="commit-message" class="yui-g">
52 <tal:no-commit-message condition="not: context/commit_message">
53 <div tal:define="link menu/set_commit_message"
54 tal:condition="link/enabled"
55 tal:content="structure link/render">
56 Set commit message
57 </div>
58 <div id="edit-commit-message" class="lazr-multiline-edit unseen"
59 tal:content="structure view/commit_message_html"/>
60 </tal:no-commit-message>
61 <tal:has-commit-message condition="context/commit_message">
62 <div tal:define="link menu/set_commit_message"
63 tal:condition="link/enabled"
64 tal:content="structure link/render" class="unseen">
65 Set commit message
66 </div>
67 <div id="edit-commit-message" class="lazr-multiline-edit"
68 tal:content="structure view/commit_message_html"/>
69 </tal:has-commit-message>
70 </div>
71
47 <div class="yui-g">72 <div class="yui-g">
48 <div id="votes-target"73 <div id="votes-target"
49 tal:content="structure context/@@+votes" />74 tal:content="structure context/@@+votes" />
@@ -67,15 +92,12 @@
67 </div>92 </div>
6893
69 <div class="yui-g">94 <div class="yui-g">
70 <div tal:define="link context/menu:context/add_comment"95 <div tal:define="link menu/add_comment"
71 tal:condition="link/enabled"96 tal:condition="link/enabled"
72 tal:content="structure link/render">97 tal:content="structure link/render">
73 Add comment98 Add comment
74 </div>99 </div>
75100
76 <div id="edit-description" class="lazr-multiline-edit"
77 tal:content="structure view/commit_message_html"/>
78
79 <div id="conversation"101 <div id="conversation"
80 tal:content="structure view/conversation/@@+render"/>102 tal:content="structure view/conversation/@@+render"/>
81 </div>103 </div>
@@ -88,7 +110,7 @@
88 </div>110 </div>
89111
90 <script type="text/javascript">112 <script type="text/javascript">
91 YUI().use('lp.comment', function(Y) {113 LPS.use('lp.comment', function(Y) {
92 var comment = new Y.lp.CodeReviewComment();114 var comment = new Y.lp.CodeReviewComment();
93 comment.render();115 comment.render();
94 })116 })
@@ -137,7 +159,7 @@
137 string:&lt;script id='codereview-script' type='text/javascript'&gt;" />159 string:&lt;script id='codereview-script' type='text/javascript'&gt;" />
138 conf = <tal:status-config replace="view/status_config" />160 conf = <tal:status-config replace="view/status_config" />
139 <!--161 <!--
140 YUI().use('io-base', 'code.codereview', 'code.branchmergeproposal',162 LPS.use('io-base', 'code.codereview', 'code.branchmergeproposal',
141 function(Y) {163 function(Y) {
142164
143165
144166
=== modified file 'lib/lp/code/windmill/tests/test_branch_merge_proposal.py'
--- lib/lp/code/windmill/tests/test_branch_merge_proposal.py 2009-11-10 18:10:12 +0000
+++ lib/lp/code/windmill/tests/test_branch_merge_proposal.py 2009-11-30 23:54:16 +0000
@@ -22,12 +22,12 @@
22# There seem to be two textareas rendered for the yui-ieditor-input for some22# There seem to be two textareas rendered for the yui-ieditor-input for some
23# reason.23# reason.
24EDIT_COMMENT_TEXTBOX = (24EDIT_COMMENT_TEXTBOX = (
25 u'//div[@id="edit-description"]//textarea[@class="yui-ieditor-input"][1]')25 u'//div[@id="edit-commit-message"]//textarea[@class="yui-ieditor-input"][1]')
26EDIT_COMMENT_SUBMIT = (26EDIT_COMMENT_SUBMIT = (
27 u'//div[@id="edit-description"]//'27 u'//div[@id="edit-commit-message"]//'
28 'button[contains(@class, "yui-ieditor-submit_button")]')28 'button[contains(@class, "yui-ieditor-submit_button")]')
29COMMIT_MESSAGE_TEXT = (29COMMIT_MESSAGE_TEXT = (
30 u'//div[@id="edit-description"]//div[@class="yui-editable_text-text"]')30 u'//div[@id="edit-commit-message"]//div[@class="yui-editable_text-text"]')
3131
3232
33class TestCommitMessage(TestCaseWithFactory):33class TestCommitMessage(TestCaseWithFactory):

Subscribers

People subscribed via source and target branches

to status/vote changes: