← Back to team overview

launchpad-reviewers team mailing list archive

Re: [Merge] lp:~cprov/launchpad/ic-superseded-mps into lp:launchpad

 

Most issues addressed.

I've proposed to postpone the event-bubbling experiment (since the change would be in the link_scroller, not IC) and the pagetest-rewrite.

Inline comments:

> --- lib/lp/app/javascript/comment.js	2014-04-04 05:23:48 +0000
> +++ lib/lp/app/javascript/comment.js	2014-05-14 20:06:59 +0000
> @@ -308,8 +308,6 @@
>      initializer: function() {
>          this.vote_input = Y.one('[id="field.vote"]');
>          this.review_type = Y.one('[id="field.review_type"]');
> -        this.publish_inline_comments = Y.one(
> -            '[id="field.publish_inline_comments"]');
>          this.in_reply_to = null;
>      },
>      /**
> @@ -334,6 +332,20 @@
>          return selected.get('innerHTML');
>      },
>      /**
> +     * Whether or not the review comment has inline comments to be published
> +     *
> +     * @method has_inline
> +     */
> +    has_inline: function() {
> +        var inline_cb = Y.one('[id="field.publish_inline_comments"]');
> +        if (inline_cb !== null) {
> +            if (inline_cb.get('checked')) {
> +                return true;
> +            }
> +        }
> +        return false;
> +    },

RIght, I had the impression the evaluation shortcut was not available in JS, but it is. Thanks for point it.

> +    /**
>       * Ensure that the widget's values are suitable for submission.
>       *
>       * This allows the vote to be submitted, even when no text is specified
> @@ -345,6 +357,9 @@
>          if (this.get_vote() !== null) {
>              return true;
>          }
> +        if (this.has_inline()) {
> +            return true
> +        }
>          return namespace.Comment.prototype.validate.apply(this);
>      },
>      /**
> @@ -357,9 +372,6 @@
>          namespace.Comment.prototype.set_disabled.call(this, disabled);
>          this.vote_input.set('disabled', disabled);
>          this.review_type.set('disabled', disabled);
> -        if (this.publish_inline_comments) {
> -            this.publish_inline_comments.set('disabled', disabled);
> -        }
>      },
>      /**
>       * Post the comment to the Launchpad API
> @@ -383,8 +395,8 @@
>          if (this.in_reply_to !== null) {
>              config.parameters.parent = this.in_reply_to.get('self_link');
>          }
> -        if (this.publish_inline_comments &&
> -            this.publish_inline_comments.get('checked')) {
> +
> +        if (this.has_inline()) {
>              var ic = Y.lp.code.branchmergeproposal.inlinecomments;
>              config.parameters.inline_comments = ic.inlinecomments;
>              config.parameters.previewdiff_id = ic.current_previewdiff_id;
> @@ -451,9 +463,6 @@
>       */
>      reset_contents: function() {
>            this.review_type.set('value', '');
> -          if (this.publish_inline_comments) {
> -              this.publish_inline_comments.set('value', '');
> -          }
>            this.vote_input.set('selectedIndex', 0);
>            this.in_reply_to = null;
>            namespace.Comment.prototype.reset_contents.apply(this);
> 
> === modified file 'lib/lp/code/browser/codereviewcomment.py'
> --- lib/lp/code/browser/codereviewcomment.py	2014-04-04 05:23:48 +0000
> +++ lib/lp/code/browser/codereviewcomment.py	2014-05-14 20:06:59 +0000
> @@ -292,18 +292,9 @@
>          """Create the comment..."""
>          vote = data.get('vote')
>          review_type = data.get('review_type')
> -        inline_comments = {}
> -        previewdiff_id = None
> -        if (getFeatureFlag('code.inline_diff_comments.enabled') and
> -            data.get('publish_inline_comments')):
> -            previewdiff_id = self.previewdiff.id
> -            inline_comments = (
> -                self.branch_merge_proposal.getDraftInlineComments(
> -                    previewdiff_id))
>          self.branch_merge_proposal.createComment(
>              self.user, subject=None, content=data['comment'],
> -            parent=self.reply_to, vote=vote, review_type=review_type,
> -            previewdiff_id=previewdiff_id, inline_comments=inline_comments)
> +            parent=self.reply_to, vote=vote, review_type=review_type)
>  
>      @property
>      def next_url(self):
> 
> === modified file 'lib/lp/code/javascript/branchmergeproposal.inlinecomments.js'
> --- lib/lp/code/javascript/branchmergeproposal.inlinecomments.js	2014-05-07 06:16:12 +0000
> +++ lib/lp/code/javascript/branchmergeproposal.inlinecomments.js	2014-05-14 20:06:59 +0000
> @@ -62,6 +62,11 @@
>                  content_row.remove(true);
>              }
>              var config = {
> +                on: {
> +                    success: function () {
> +                        Y.fire('inlinecomment.UPDATED');
> +                    }
> +                },
>                  parameters: {
>                      previewdiff_id: namespace.current_previewdiff_id,
>                      comments: namespace.inlinecomments
> @@ -161,8 +166,8 @@
>  namespace.cleanup_comments = function() {
>      // Cleanup previous inline review comments.
>      Y.all('.ict-header').each( function(line) {
> -        line.next().remove();
> -        line.remove();
> +        line.next().remove(true);
> +        line.remove(true);
>      });
>  };
>  
> @@ -176,6 +181,7 @@
>                  comments.forEach( function (comment) {
>                      namespace.create_row(comment);
>                  });
> +                Y.fire('inlinecomment.UPDATED');
>              }
>          },
>          parameters: {
> @@ -203,6 +209,7 @@
>                      };
>                      namespace.create_row(comment);
>                  });
> +                Y.fire('inlinecomment.UPDATED');
>              }
>          },
>          parameters: {
> @@ -237,6 +244,63 @@
>  };
>  
>  
> +var PublishDrafts = function () {
> +    PublishDrafts.superclass.constructor.apply(this, arguments);
> +};
> +
> +Y.mix(PublishDrafts, {
> +
> +    NAME: 'publishdrafts',
> +
> +    ATTRS: {
> +    }
> +
> +});
> +
> +Y.extend(PublishDrafts, Y.Widget, {
> +
> +    renderUI: function() {
> +        if (Y.one('#publish_drafts_container')) {
> +            return;

I could not tell the difference between 'srcNode' and 'contentBox' from the YUI3 docs. Since 'srcNode' seems to be the choice of other existing widget, I am using it.
Does it sound correct ?

> +        }
> +        var container = Y.Node.create('<div />')
> +            .set('id', 'publish_drafts_container');
> +        this.get('srcNode').insert(container, 'after');
> +    },
> +
> +    updateUI: function() {
> +        var container = Y.one('#publish_drafts_container')
> +        container.empty();

'srcNode', ditto

> +
> +        var n_drafts = Y.all('.draft').size();
> +        Y.log(n_drafts + ' drafts');
> +        if (n_drafts == 0) {
> +            return;
> +        }
> +        var label = Y.Node.create('<a />')
> +            .set('text', 'Publish ' + n_drafts + ' inline comments');
> +        var checkbox = Y.Node.create('<input />')
> +            .set('id', 'field.publish_inline_comments')
> +            .set('name', 'field.publish_inline_comments')
> +            .set('type', 'checkbox')
> +            .set('checked', true)
> +            .addClass('checkboxType');
> +        container.append(checkbox);

fixed.

> +        container.append(label);
> +        Y.one('[id="field.actions.add"]').set('disabled', false)
> +    },

Right, now we have 'CodeReviewComment.SET_DISABLED', but unfortunately it could not use this.set_disabled() implementation, since it also disables the textarea, so the user cannot recover from it.

> +
> +    bindUI: function() {
> +        var self = this;
> +        Y.detach('inlinecomment.UPDATED');

it's  used now since the updateUI() method uses this.get('srcNode').

> +        Y.on('inlinecomment.UPDATED', this.updateUI);
> +    }
> +
> +});
> +
> +namespace.PublishDrafts = PublishDrafts;
> +
> +
>  var InlineCommentToggle = function () {
>      InlineCommentToggle.superclass.constructor.apply(this, arguments);
>  };
> @@ -383,7 +447,7 @@
>       * @method cleanup_status
>       */
>      cleanup_status: function() {
> -        this.get('srcNode').all('h2 img').remove();
> +        this.get('srcNode').all('h2 img').remove(true);
>      },
>  
>      /**
> @@ -395,6 +459,7 @@
>          if (LP.cache.inline_diff_comments !== true) {
>              return;
>          }
> +        namespace.cleanup_comments();
>          namespace.populate_comments();
>          this._connectScrollers();
>      },
> @@ -408,10 +473,29 @@
>      _connectScrollers: function() {
>          var self = this;
>          var rc = Y.lp.code.branchmergeproposal.reviewcomment;
> -        Y.all('.inline-comment-scroller').each( function(node) {
> +        Y.all('td[data-previewdiff-id]').each( function(td) {
> +            // Comments from superseded MPs should be ignored.
> +            if (td.getAttribute('data-from-superseded') === 'True') {
> +                return;

Cool! Thanks

> +            }
> +            var previewdiff_id = td.getAttribute('data-previewdiff-id');
> +            var comment_id = td.getAttribute('data-comment-id');
> +            var scroller_id = (
> +                'ic-scroller-' + previewdiff_id + '-' + comment_id);
> +            // We have to remove the old scrollers otherwise they will
> +            // fire multiple 'click' handlers (and animations).
> +            var node = Y.one('#' + scroller_id)

Right, event bubbling would solve my problem if I was using the original click handler directly, but I am using it via the link_scroller() ...
I propose we carry on with they problem in this branch and attack it more aggressively on the JS-refactoring iteration (hopefully post release). 
What do you think ?

> +            if (node !== null) {
> +               node.remove(true);
> +            }
> +            node = Y.Node.create('<a />')
> +                .set('id', scroller_id)
> +                .set('href', '')
> +                .set('text', 'View inline comments')
> +                .setStyle('float', 'right');
> +            td.append(node);
>              rc.link_scroller(node, '#review-diff', function() {
> -                self._showPreviewDiff(
> -                    node.getAttribute('data-previewdiff-id'));
> +                self._showPreviewDiff(previewdiff_id);
>              });
>          });
>      },
> @@ -488,6 +572,8 @@
>              self._updateDiff(preview_diff_uri);
>              return;
>          }
> +        (new namespace.PublishDrafts(
> +            {'srcNode': Y.one('[id="field.review_type"]')})).render();
>          var container = this.get('srcNode').one('.diff-navigator');
>          container.empty();
>          var preview_diffs_uri = LP.cache.context.preview_diffs_collection_link;
> 
> === modified file 'lib/lp/code/javascript/tests/test_branchmergeproposal.inlinecomments.html'
> --- lib/lp/code/javascript/tests/test_branchmergeproposal.inlinecomments.html	2014-04-03 20:33:08 +0000
> +++ lib/lp/code/javascript/tests/test_branchmergeproposal.inlinecomments.html	2014-05-14 20:06:59 +0000
> @@ -72,11 +72,30 @@
>              <li>lp.code.branchmergeproposal.inlinecomments.test</li>
>          </ul>
>  
> -      <a id="scroll-one" class="inline-comment-scroller" href=""
> -         data-previewdiff-id="101">Go to One</a>
> +      <div>
> +        <input id="field.review_type" type="text"></input>
> +        <input id="field.actions.add" type="submit" value="Save"></input>
> +      </div>
>  
> -      <a id="scroll-two" class="inline-comment-scroller" href=""
> -         data-previewdiff-id="202">Go to Two</a>
> +      <table class="conversation">
> +      <tr>
> +        <td data-previewdiff-id="102" data-from-superseded="True"
> +            data-comment-id="10">
> +           Comment from superseded </td>
> +      </tr><tr>
> +        <td data-previewdiff-id="101" data-from-superseded="False"
> +            data-comment-id="1">
> +           Comment One </td>
> +      </tr><tr>
> +        <td data-previewdiff-id="202" data-from-superseded="False"
> +            data-comment-id="2">
> +           Comment Two </td>
> +      </tr><tr>
> +        <td data-from-superseded="False"
> +            data-comment-id="3">
> +           No inlines </td>
> +      </tr>
> +      </table>
>  
>        <div id="review-diff">
>  
> 
> === modified file 'lib/lp/code/javascript/tests/test_branchmergeproposal.inlinecomments.js'
> --- lib/lp/code/javascript/tests/test_branchmergeproposal.inlinecomments.js	2014-05-07 06:16:12 +0000
> +++ lib/lp/code/javascript/tests/test_branchmergeproposal.inlinecomments.js	2014-05-14 20:06:59 +0000
> @@ -408,6 +408,26 @@
>                  'table-row', Y.one('tr.ict-header').getStyle('display'));
>          },
>  
> +        test_publish_drafts: function() {
> +            // PublishDraft() widget modified the add-comment form
> +            // (adding/removing 'publish_inlines' checkbox) according
> +            // to the existance of draft inline comments.
> +            var container = Y.one('#publish_drafts_container')
> +            Y.Assert.areEqual('', container.get('text'));
> +            Y.Assert.isNull(container.one('[type=checkbox]'));
> +
> +            // A event is fired when the inlinecomments set changes.
> +            Y.fire('inlinecomment.UPDATED');
> +            Y.Assert.areEqual(
> +                 'Publish 1 inline comments', container.get('text'));
> +            Y.Assert.isNotNull(container.one('[type=checkbox]'));
> +
> +            module.cleanup_comments();
> +            Y.fire('inlinecomment.UPDATED');
> +            Y.Assert.areEqual('', container.get('text'));
> +            Y.Assert.isNull(container.one('[type=checkbox]'));
> +        },
> +
>          test_diff_nav_scrollers: function() {
>              // The Diff Navigator review comment *scrollers* are connected
>              // upon widget rendering and when clicked trigger the diff
> @@ -417,10 +437,25 @@
>              this.reply_diffcontent();
>              var mockio = this.diffnav.get('lp_client').io_provider;
>              Y.Assert.areEqual(2, mockio.requests.length);
> +            // The needed review-comment scrollers (View inline comments)
> +            // are created. Only 'current' (non-superseded) comments
> +            // associated with inline comments get a scroller.
> +            var lines = []
> +            Y.one('.conversation').get('text').split('\n').forEach(
> +                function(line) { if (line.trim()) lines.push(line.trim()); }
> +            );
> +            Y.ArrayAssert.itemsAreEqual(
> +                ['Comment from superseded',
> +                 'Comment One View inline comments',
> +                 'Comment Two View inline comments',
> +                 'No inlines'],
> +                lines);
> +            // Scroller are identified as:
> +            // 'ic-scroller-<previewdiff_id>-<comment_id>'.
> +            var scroller = Y.one('#ic-scroller-202-2');
>              // We need to re-instrument the scroller in other to
>              // instantly fire the 'end' event (which runs the code
>              // that matters to us).
> -            scroller = Y.one('#scroll-two');
>              scroller.on('click', function() {
>                  var rc = Y.lp.code.branchmergeproposal.reviewcomment;
>                  rc.window_scroll_anim.fire('end');
> @@ -446,20 +481,27 @@
>              // hook new inline-comment scroller links.
>              this.diffnav.set('navigator', Y.one('select'));
>              // Let's create add a new scroller to the page.
> -            var new_scroller = Y.Node.create(
> -                '<a id="scroll-three" class="inline-comment-scroller" ' +
> -                'href="" data-previewdiff-id="202">Another scroller</a>');
> -            Y.one('#scroll-two').insert(new_scroller, 'after');
> -            // and instrument the inline-comment updated function.
> +            var new_comment = Y.Node.create(
> +                '<tr><td data-previewdiff-id="202" data-comment-id="3">' +
> +                'Comment Three</td></tr>');
> +            Y.one('.conversation').append(new_comment);
> +            // and instrument the inline-comment functions to remove
> +            // and populate comments.
> +            var cleaned = false;
>              var populated = false;
> +            module.cleanup_comments = function () {
> +                cleaned = true;
> +            };
>              module.populate_comments = function () {
>                  populated = true;
>              };
> -            // Once called, update_on_new_comment() integrates the
> -            // just-added scroller and updates the inline comments.
> +            // Once called, update_on_new_comment() creates the scroller
> +            // for the just-added comment and refreshes the inline comments.
>              this.diffnav.update_on_new_comment();
> +            var new_scroller = Y.one('#ic-scroller-202-3');
>              Y.Assert.isTrue(new_scroller.hasClass('js-action'));
>              Y.Assert.isTrue(populated);
> +            Y.Assert.isTrue(cleaned);
>              // Instrument the new scroller, so it will instantly fire
>              // the diff navigator hook and register the requested diff.
>              new_scroller.on('click', function() {
> 
> === modified file 'lib/lp/code/stories/branches/xx-code-review-comments.txt'
> --- lib/lp/code/stories/branches/xx-code-review-comments.txt	2012-01-15 13:32:27 +0000
> +++ lib/lp/code/stories/branches/xx-code-review-comments.txt	2014-05-14 20:06:59 +0000
> @@ -189,3 +189,84 @@
>      Testing commits in conversation
>      4. By ... on 2009-09-12
>      and it works!
> +
> +
> +Inline Comments
> +---------------
> +

Can I postpone this move too ?

> +The code review inline comments support is entirely implemented in
> +Javascript. The current implementation relies on comments being
> +rendered with the following 'data-' attributes:
> +
> +    # Created a new review comment with associated inline comments
> +    # on the superseded and on the new MP.
> +    >>> from lp.services.features.testing import FeatureFixture
> +    >>> fixture = FeatureFixture(
> +    ...     {'code.inline_diff_comments.enabled': 'enabled'})
> +
> +    >>> login('foo.bar@xxxxxxxxxxxxx')
> +    >>> fixture.setUp()
> +    >>> previewdiff = factory.makePreviewDiff(merge_proposal=merge_proposal)
> +    >>> new_previewdiff = factory.makePreviewDiff(
> +    ...     merge_proposal=new_merge_proposal)
> +    >>> transaction.commit()
> +    >>> comment = merge_proposal.createComment(
> +    ...    eric, None, content='a_content',
> +    ...    previewdiff_id=previewdiff.id,
> +    ...    inline_comments={'1': 'No!'}
> +    ... )
> +    >>> transaction.commit()
> +    >>> comment = new_merge_proposal.createComment(
> +    ...    eric, None, content='a_content',
> +    ...    previewdiff_id=new_previewdiff.id,
> +    ...    inline_comments={'1': 'Yes!'}
> +    ... )
> +    >>> fixture.cleanUp()
> +    >>> logout()
> +
> +    # helper for printing review comment 'data-' attributes.
> +    >>> def print_comment_attributes(contents):
> +    ...     comments = find_tags_by_class(contents, 'boardCommentDetails')
> +    ...     print 'Text', 'Comment', 'Diff', 'Superseded'
> +    ...     for comment in comments:
> +    ...         tds = comment.findAll('td')
> +    ...         if len(tds) == 0:
> +    ...            continue
> +    ...         td = tds[0]
> +    ...         print ' '.join(
> +    ...             (extract_text(td),
> +    ...              td['data-comment-id'],
> +    ...              td.get('data-previewdiff-id', '-'),
> +    ...              td.get('data-from-superseded', '-')))
> +
> +The 'data-' attributes:
> +
> + * 'comment-id': The review comment ID, used to highlight related
> + *               inline comments.
> + * 'previewdiff-id': used to load the corresponding `PreviewDiff`.
> + * 'from_superseded': 'True' or 'False' whether the context MP is
> +                      superseded by another. Used to supress context
> +                      handlers on superseded comments.
> +
> +They are always available in `BranchMergeProposal` pages.
> +
> +    >>> anon_browser.open(merge_proposal_url)
> +    >>> print_comment_attributes(anon_browser.contents)
> +    Text    Comment Diff Superseded
> +    Eric...     1     -    False
> +    Eric...     2     -    False
> +    Eric...     3     -    False
> +    Eric...     4     1    False
> +
> +When visualized in the new merge proposal the comments from the original
> +merge proposal are marked as 'superseded' and there is a new and
> +non-superseded local comment.
> +
> +    >>> anon_browser.open(new_merge_proposal_url)
> +    >>> print_comment_attributes(anon_browser.contents)
> +    Text    Comment Diff Superseded
> +    Eric...     1     -    True
> +    Eric...     2     -    True
> +    Eric...     3     -    True
> +    Eric...     4     1    True
> +    Eric...     5     2    False
> 
> === modified file 'lib/lp/code/templates/branchmergeproposal-index.pt'
> --- lib/lp/code/templates/branchmergeproposal-index.pt	2014-04-04 04:47:15 +0000
> +++ lib/lp/code/templates/branchmergeproposal-index.pt	2014-05-14 20:06:59 +0000
> @@ -144,7 +144,6 @@
>          <div id="add-comment-review-fields">
>              Review: <tal:review replace="structure comment_form/widgets/vote"/>
>              Review type: <tal:review replace="structure comment_form/widgets/review_type"/>
> -            <tal:publish_inline_comments condition="features/code.inline_diff_comments.enabled">Publish inline comments: <tal:review replace="structure comment_form/widgets/publish_inline_comments" tal:condition="features/code.inline_diff_comments.enabled"/></tal:publish_inline_comments>
>              <div class="actions"
>                   tal:content="structure comment_form/actions/field.actions.add/render" />
>          </div>
> 
> === modified file 'lib/lp/code/templates/codereviewcomment-header.pt'
> --- lib/lp/code/templates/codereviewcomment-header.pt	2014-04-03 20:33:08 +0000
> +++ lib/lp/code/templates/codereviewcomment-header.pt	2014-05-14 20:06:59 +0000
> @@ -6,7 +6,9 @@
>  <table>
>    <tbody>
>      <tr>
> -    <td>
> +    <td tal:attributes="data-previewdiff-id context/previewdiff_id;
> +                        data-from-superseded context/from_superseded;
> +                        data-comment-id context/id">
>        <span
>          itemprop="creator"
>          tal:content="structure context/comment_author/fmt:link-display-name-id"/>
> @@ -26,11 +28,6 @@
>                tal:attributes="href context/branch_merge_proposal/fmt:url">a
>                previous version</a>
>              of this proposal</span>
> -        <span style="float: right;" tal:condition="context/previewdiff_id">
> -          <a class="inline-comment-scroller" href=""
> -             tal:attributes="data-previewdiff-id context/previewdiff_id"
> -            >View inline comments</a>
> -        </span>
>        </td>
>  
>        <td class="bug-comment-index">
> 


-- 
https://code.launchpad.net/~cprov/launchpad/ic-superseded-mps/+merge/219431
Your team Launchpad code reviewers is subscribed to branch lp:launchpad.


References