jump_to_discussion.js.es6 6.45 KB
Newer Older
1
/* eslint-disable comma-dangle, object-shorthand, func-names, no-else-return, guard-for-in, no-restricted-syntax, one-var, indent, space-before-function-paren, no-lonely-if, no-continue, brace-style, max-len, quotes */
2 3 4 5
/* global Vue */
/* global DiscussionMixins */
/* global CommentsStore */

6
(() => {
7
  const JumpToDiscussion = Vue.extend({
8
    mixins: [DiscussionMixins],
9 10 11
    props: {
      discussionId: String
    },
12 13 14 15 16
    data: function () {
      return {
        discussions: CommentsStore.state,
      };
    },
17
    computed: {
18 19
      discussion: function () {
        return this.discussions[this.discussionId];
20
      },
21
      allResolved: function () {
22
        return this.unresolvedDiscussionCount === 0;
23 24
      },
      showButton: function () {
25 26 27 28
        if (this.discussionId) {
          if (this.unresolvedDiscussionCount > 1) {
            return true;
          } else {
29
            return this.discussionId !== this.lastResolvedId;
30 31 32 33
          }
        } else {
          return this.unresolvedDiscussionCount >= 1;
        }
34
      },
35 36 37 38 39 40 41 42 43 44
      lastResolvedId: function () {
        let lastId;
        for (const discussionId in this.discussions) {
          const discussion = this.discussions[discussionId];

          if (!discussion.isResolved()) {
            lastId = discussion.id;
          }
        }
        return lastId;
45 46 47
      }
    },
    methods: {
48
      jumpToNextUnresolvedDiscussion: function () {
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
        let discussionsSelector,
            discussionIdsInScope,
            firstUnresolvedDiscussionId,
            nextUnresolvedDiscussionId,
            activeTab = window.mrTabs.currentAction,
            hasDiscussionsToJumpTo = true,
            jumpToFirstDiscussion = !this.discussionId;

        const discussionIdsForElements = function(elements) {
          return elements.map(function() {
            return $(this).attr('data-discussion-id');
          }).toArray();
        };

        const discussions = this.discussions;

        if (activeTab === 'diffs') {
          discussionsSelector = '.diffs .notes[data-discussion-id]';
          discussionIdsInScope = discussionIdsForElements($(discussionsSelector));
68

69
          let unresolvedDiscussionCount = 0;
70

71
          for (let i = 0; i < discussionIdsInScope.length; i += 1) {
Connor Shea's avatar
Connor Shea committed
72
            const discussionId = discussionIdsInScope[i];
73
            const discussion = discussions[discussionId];
74
            if (discussion && !discussion.isResolved()) {
75
              unresolvedDiscussionCount += 1;
76
            }
77 78
          }

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
          if (this.discussionId && !this.discussion.isResolved()) {
            // If this is the last unresolved discussion on the diffs tab,
            // there are no discussions to jump to.
            if (unresolvedDiscussionCount === 1) {
              hasDiscussionsToJumpTo = false;
            }
          } else {
            // If there are no unresolved discussions on the diffs tab at all,
            // there are no discussions to jump to.
            if (unresolvedDiscussionCount === 0) {
              hasDiscussionsToJumpTo = false;
            }
          }
        } else if (activeTab !== 'notes') {
          // If we are on the commits or builds tabs,
          // there are no discussions to jump to.
          hasDiscussionsToJumpTo = false;
        }
97

98 99 100 101 102 103 104
        if (!hasDiscussionsToJumpTo) {
          // If there are no discussions to jump to on the current page,
          // switch to the notes tab and jump to the first disucssion there.
          window.mrTabs.activateTab('notes');
          activeTab = 'notes';
          jumpToFirstDiscussion = true;
        }
105

106 107 108 109 110 111
        if (activeTab === 'notes') {
          discussionsSelector = '.discussion[data-discussion-id]';
          discussionIdsInScope = discussionIdsForElements($(discussionsSelector));
        }

        let currentDiscussionFound = false;
112
        for (let i = 0; i < discussionIdsInScope.length; i += 1) {
Connor Shea's avatar
Connor Shea committed
113
          const discussionId = discussionIdsInScope[i];
114 115 116 117 118
          const discussion = discussions[discussionId];

          if (!discussion) {
            // Discussions for comments on commits in this MR don't have a resolved status.
            continue;
119
          }
120

121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
          if (!firstUnresolvedDiscussionId && !discussion.isResolved()) {
            firstUnresolvedDiscussionId = discussionId;

            if (jumpToFirstDiscussion) {
              break;
            }
          }

          if (!jumpToFirstDiscussion) {
            if (currentDiscussionFound) {
              if (!discussion.isResolved()) {
                nextUnresolvedDiscussionId = discussionId;
                break;
              }
              else {
                continue;
              }
            }

            if (discussionId === this.discussionId) {
              currentDiscussionFound = true;
            }
          }
        }

        nextUnresolvedDiscussionId = nextUnresolvedDiscussionId || firstUnresolvedDiscussionId;

        if (!nextUnresolvedDiscussionId) {
          return;
        }

        let $target = $(`${discussionsSelector}[data-discussion-id="${nextUnresolvedDiscussionId}"]`);

        if (activeTab === 'notes') {
          $target = $target.closest('.note-discussion');
Connor Shea's avatar
Connor Shea committed
156 157 158

          // If the next discussion is closed, toggle it open.
          if ($target.find('.js-toggle-content').is(':hidden')) {
159
            $target.find('.js-toggle-button i').trigger('click');
Connor Shea's avatar
Connor Shea committed
160
          }
161 162 163 164 165 166 167 168 169 170 171 172
        } else if (activeTab === 'diffs') {
          // Resolved discussions are hidden in the diffs tab by default.
          // If they are marked unresolved on the notes tab, they will still be hidden on the diffs tab.
          // When jumping between unresolved discussions on the diffs tab, we show them.
          $target.closest(".content").show();

          $target = $target.closest("tr.notes_holder");
          $target.show();

          // If we are on the diffs tab, we don't scroll to the discussion itself, but to
          // 4 diff lines above it: the line the discussion was in response to + 3 context
          let prevEl;
173
          for (let i = 0; i < 4; i += 1) {
174 175 176 177 178 179 180 181 182
            prevEl = $target.prev();

            // If the discussion doesn't have 4 lines above it, we'll have to do with fewer.
            if (!prevEl.hasClass("line_holder")) {
              break;
            }

            $target = prevEl;
          }
183
        }
184 185 186 187

        $.scrollTo($target, {
          offset: -($('.navbar-gitlab').outerHeight() + $('.layout-nav').outerHeight())
        });
188
      }
189 190 191 192
    }
  });

  Vue.component('jump-to-discussion', JumpToDiscussion);
193
})();