BigW Consortium Gitlab

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

import Vue from 'vue';
6

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

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

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

68
      const discussions = this.discussions;
69

70 71 72 73 74
      if (activeTab === 'diffs') {
        discussionsSelector = '.diffs .notes[data-discussion-id]';
        discussionIdsInScope = discussionIdsForElements($(discussionsSelector));

        let unresolvedDiscussionCount = 0;
75

76
        for (let i = 0; i < discussionIdsInScope.length; i += 1) {
Connor Shea committed
77
          const discussionId = discussionIdsInScope[i];
78
          const discussion = discussions[discussionId];
79 80 81 82
          if (discussion && !discussion.isResolved()) {
            unresolvedDiscussionCount += 1;
          }
        }
83

84 85 86 87 88 89 90 91 92 93 94
        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;
95
          }
96
        }
97
      } else if (activeTab !== 'show') {
98 99 100 101
        // If we are on the commits or builds tabs,
        // there are no discussions to jump to.
        hasDiscussionsToJumpTo = false;
      }
102

103 104 105
      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.
106 107
        window.mrTabs.activateTab('show');
        activeTab = 'show';
108 109
        jumpToFirstDiscussion = true;
      }
110

111
      if (activeTab === 'show') {
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
        discussionsSelector = '.discussion[data-discussion-id]';
        discussionIdsInScope = discussionIdsForElements($(discussionsSelector));
      }

      let currentDiscussionFound = false;
      for (let i = 0; i < discussionIdsInScope.length; i += 1) {
        const discussionId = discussionIdsInScope[i];
        const discussion = discussions[discussionId];

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

        if (!firstUnresolvedDiscussionId && !discussion.isResolved()) {
          firstUnresolvedDiscussionId = discussionId;

          if (jumpToFirstDiscussion) {
            break;
131
          }
132
        }
133

134 135 136 137 138
        if (!jumpToFirstDiscussion) {
          if (currentDiscussionFound) {
            if (!discussion.isResolved()) {
              nextUnresolvedDiscussionId = discussionId;
              break;
139
            }
140 141
            else {
              continue;
142 143
            }
          }
144 145 146 147

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

151
      nextUnresolvedDiscussionId = nextUnresolvedDiscussionId || firstUnresolvedDiscussionId;
152

153 154 155
      if (!nextUnresolvedDiscussionId) {
        return;
      }
156

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

159
      if (activeTab === 'show') {
160
        $target = $target.closest('.note-discussion');
Connor Shea committed
161

162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
        // If the next discussion is closed, toggle it open.
        if ($target.find('.js-toggle-content').is(':hidden')) {
          $target.find('.js-toggle-button i').trigger('click');
        }
      } 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;
        for (let i = 0; i < 4; i += 1) {
          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;
Connor Shea committed
184
          }
185

186
          $target = prevEl;
187 188
        }
      }
189

190 191 192 193 194 195 196 197 198 199 200
      $.scrollTo($target, {
        offset: 0
      });
    }
  },
  created() {
    this.discussion = this.discussions[this.discussionId];
  },
});

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