summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/visual_review_toolbar/components/comment_post.js
blob: ee5f2b62425a90b08360944a9e9a6986d34db824 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
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
import { BLACK, COMMENT_BOX, MUTED } from '../shared';
import { clearSavedComment } from './comment_storage';
import { clearNote, postError } from './note';
import { selectCommentBox, selectCommentButton, selectNote, selectNoteContainer } from './utils';

const resetCommentButton = () => {
  const commentButton = selectCommentButton();

  /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
  commentButton.innerText = 'Send feedback';
  commentButton.classList.replace('gitlab-button-secondary', 'gitlab-button-success');
  commentButton.style.opacity = 1;
};

const resetCommentBox = () => {
  const commentBox = selectCommentBox();
  commentBox.style.pointerEvents = 'auto';
  commentBox.style.color = BLACK;
};

const resetCommentText = () => {
  const commentBox = selectCommentBox();
  commentBox.value = '';
  clearSavedComment();
};

const resetComment = () => {
  resetCommentButton();
  resetCommentBox();
  resetCommentText();
};

const confirmAndClear = feedbackInfo => {
  const commentButton = selectCommentButton();
  const currentNote = selectNote();
  const noteContainer = selectNoteContainer();

  /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
  commentButton.innerText = 'Feedback sent';
  noteContainer.style.visibility = 'visible';
  currentNote.insertAdjacentHTML('beforeend', feedbackInfo);

  setTimeout(resetComment, 1000);
  setTimeout(clearNote, 6000);
};

const setInProgressState = () => {
  const commentButton = selectCommentButton();
  const commentBox = selectCommentBox();

  /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
  commentButton.innerText = 'Sending feedback';
  commentButton.classList.replace('gitlab-button-success', 'gitlab-button-secondary');
  commentButton.style.opacity = 0.5;
  commentBox.style.color = MUTED;
  commentBox.style.pointerEvents = 'none';
};

const commentErrors = error => {
  switch (error.status) {
    case 401:
      /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
      return 'Unauthorized. You may have entered an incorrect authentication token.';
    case 404:
      /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
      return 'Not found. You may have entered an incorrect merge request ID.';
    default:
      /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
      return `Your comment could not be sent. Please try again. Error: ${error.message}`;
  }
};

const postComment = ({
  platform,
  browser,
  userAgent,
  innerWidth,
  innerHeight,
  projectId,
  projectPath,
  mergeRequestId,
  mrUrl,
  token,
}) => {
  // Clear any old errors
  clearNote(COMMENT_BOX);

  setInProgressState();

  const commentText = selectCommentBox().value.trim();
  // Get the href at the last moment to support SPAs
  const { href } = window.location;

  if (!commentText) {
    /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
    postError('Your comment appears to be empty.', COMMENT_BOX);
    resetCommentBox();
    resetCommentButton();
    return;
  }

  const detailText = `
 \n
<details>
  <summary>Metadata</summary>
  Posted from ${href} | ${platform} | ${browser} | ${innerWidth} x ${innerHeight}.
  <br /><br />
  <em>User agent: ${userAgent}</em>
</details>
  `;

  const url = `
    ${mrUrl}/api/v4/projects/${projectId}/merge_requests/${mergeRequestId}/discussions`;

  const body = `${commentText} ${detailText}`;

  fetch(url, {
    method: 'POST',
    headers: {
      'PRIVATE-TOKEN': token,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ body }),
  })
    .then(response => {
      if (response.ok) {
        return response.json();
      }

      throw response;
    })
    .then(data => {
      const commentId = data.notes[0].id;
      const feedbackLink = `${mrUrl}/${projectPath}/merge_requests/${mergeRequestId}#note_${commentId}`;
      const feedbackInfo = `Feedback sent. View at <a class="gitlab-link" href="${feedbackLink}">${projectPath} !${mergeRequestId} (comment ${commentId})</a>`;
      confirmAndClear(feedbackInfo);
    })
    .catch(err => {
      postError(commentErrors(err), COMMENT_BOX);
      resetCommentBox();
      resetCommentButton();
    });
};

export default postComment;