/app/assets/javascripts/notes/stores/mutations.js

https://gitlab.com/artofhuman/gitlab-ce · JavaScript · 264 lines · 216 code · 44 blank · 4 comment · 30 complexity · 857ca8ec49348d39a09bc7e5c952de7f MD5 · raw file

  1. import * as utils from './utils';
  2. import * as types from './mutation_types';
  3. import * as constants from '../constants';
  4. import { isInMRPage } from '../../lib/utils/common_utils';
  5. export default {
  6. [types.ADD_NEW_NOTE](state, data) {
  7. const note = data.discussion ? data.discussion.notes[0] : data;
  8. const { discussion_id, type } = note;
  9. const [exists] = state.discussions.filter(n => n.id === note.discussion_id);
  10. const isDiscussion = type === constants.DISCUSSION_NOTE || type === constants.DIFF_NOTE;
  11. if (!exists) {
  12. const noteData = {
  13. expanded: true,
  14. id: discussion_id,
  15. individual_note: !isDiscussion,
  16. notes: [note],
  17. reply_id: discussion_id,
  18. };
  19. if (isDiscussion && isInMRPage()) {
  20. noteData.resolvable = note.resolvable;
  21. noteData.resolved = false;
  22. noteData.active = true;
  23. noteData.resolve_path = note.resolve_path;
  24. noteData.resolve_with_issue_path = note.resolve_with_issue_path;
  25. noteData.diff_discussion = false;
  26. }
  27. state.discussions.push(noteData);
  28. }
  29. },
  30. [types.ADD_NEW_REPLY_TO_DISCUSSION](state, note) {
  31. const noteObj = utils.findNoteObjectById(state.discussions, note.discussion_id);
  32. if (noteObj) {
  33. noteObj.notes.push(note);
  34. }
  35. },
  36. [types.DELETE_NOTE](state, note) {
  37. const noteObj = utils.findNoteObjectById(state.discussions, note.discussion_id);
  38. if (noteObj.individual_note) {
  39. state.discussions.splice(state.discussions.indexOf(noteObj), 1);
  40. } else {
  41. const comment = utils.findNoteObjectById(noteObj.notes, note.id);
  42. noteObj.notes.splice(noteObj.notes.indexOf(comment), 1);
  43. if (!noteObj.notes.length) {
  44. state.discussions.splice(state.discussions.indexOf(noteObj), 1);
  45. }
  46. }
  47. },
  48. [types.EXPAND_DISCUSSION](state, { discussionId }) {
  49. const discussion = utils.findNoteObjectById(state.discussions, discussionId);
  50. Object.assign(discussion, { expanded: true });
  51. },
  52. [types.COLLAPSE_DISCUSSION](state, { discussionId }) {
  53. const discussion = utils.findNoteObjectById(state.discussions, discussionId);
  54. Object.assign(discussion, { expanded: false });
  55. },
  56. [types.REMOVE_PLACEHOLDER_NOTES](state) {
  57. const { discussions } = state;
  58. for (let i = discussions.length - 1; i >= 0; i -= 1) {
  59. const note = discussions[i];
  60. const children = note.notes;
  61. if (children.length && !note.individual_note) {
  62. // remove placeholder from discussions
  63. for (let j = children.length - 1; j >= 0; j -= 1) {
  64. if (children[j].isPlaceholderNote) {
  65. children.splice(j, 1);
  66. }
  67. }
  68. } else if (note.isPlaceholderNote) {
  69. // remove placeholders from state root
  70. discussions.splice(i, 1);
  71. }
  72. }
  73. },
  74. [types.SET_NOTES_DATA](state, data) {
  75. Object.assign(state, { notesData: data });
  76. },
  77. [types.SET_NOTEABLE_DATA](state, data) {
  78. Object.assign(state, { noteableData: data });
  79. },
  80. [types.SET_USER_DATA](state, data) {
  81. Object.assign(state, { userData: data });
  82. },
  83. [types.SET_INITIAL_DISCUSSIONS](state, discussionsData) {
  84. const discussions = discussionsData.reduce((acc, d) => {
  85. const discussion = { ...d };
  86. const diffData = {};
  87. if (discussion.diff_file) {
  88. diffData.file_hash = discussion.diff_file.file_hash;
  89. diffData.truncated_diff_lines = discussion.truncated_diff_lines || [];
  90. }
  91. // To support legacy notes, should be very rare case.
  92. if (discussion.individual_note && discussion.notes.length > 1) {
  93. discussion.notes.forEach(n => {
  94. acc.push({
  95. ...discussion,
  96. ...diffData,
  97. notes: [n], // override notes array to only have one item to mimick individual_note
  98. });
  99. });
  100. } else {
  101. const oldNote = utils.findNoteObjectById(state.discussions, discussion.id);
  102. acc.push({
  103. ...discussion,
  104. ...diffData,
  105. expanded: oldNote ? oldNote.expanded : discussion.expanded,
  106. });
  107. }
  108. return acc;
  109. }, []);
  110. Object.assign(state, { discussions });
  111. },
  112. [types.SET_LAST_FETCHED_AT](state, fetchedAt) {
  113. Object.assign(state, { lastFetchedAt: fetchedAt });
  114. },
  115. [types.SET_TARGET_NOTE_HASH](state, hash) {
  116. Object.assign(state, { targetNoteHash: hash });
  117. },
  118. [types.SHOW_PLACEHOLDER_NOTE](state, data) {
  119. let notesArr = state.discussions;
  120. const existingDiscussion = utils.findNoteObjectById(notesArr, data.replyId);
  121. if (existingDiscussion) {
  122. notesArr = existingDiscussion.notes;
  123. }
  124. notesArr.push({
  125. individual_note: true,
  126. isPlaceholderNote: true,
  127. placeholderType: data.isSystemNote ? constants.SYSTEM_NOTE : constants.NOTE,
  128. notes: [
  129. {
  130. body: data.noteBody,
  131. },
  132. ],
  133. });
  134. },
  135. [types.TOGGLE_AWARD](state, data) {
  136. const { awardName, note } = data;
  137. const { id, name, username } = state.userData;
  138. const hasEmojiAwardedByCurrentUser = note.award_emoji.filter(
  139. emoji => emoji.name === data.awardName && emoji.user.id === id,
  140. );
  141. if (hasEmojiAwardedByCurrentUser.length) {
  142. // If current user has awarded this emoji, remove it.
  143. note.award_emoji.splice(note.award_emoji.indexOf(hasEmojiAwardedByCurrentUser[0]), 1);
  144. } else {
  145. note.award_emoji.push({
  146. name: awardName,
  147. user: { id, name, username },
  148. });
  149. }
  150. },
  151. [types.TOGGLE_DISCUSSION](state, { discussionId, forceExpanded = null }) {
  152. const discussion = utils.findNoteObjectById(state.discussions, discussionId);
  153. Object.assign(discussion, {
  154. expanded: forceExpanded === null ? !discussion.expanded : forceExpanded,
  155. });
  156. },
  157. [types.UPDATE_NOTE](state, note) {
  158. const noteObj = utils.findNoteObjectById(state.discussions, note.discussion_id);
  159. if (noteObj.individual_note) {
  160. noteObj.notes.splice(0, 1, note);
  161. } else {
  162. const comment = utils.findNoteObjectById(noteObj.notes, note.id);
  163. noteObj.notes.splice(noteObj.notes.indexOf(comment), 1, note);
  164. }
  165. },
  166. [types.APPLY_SUGGESTION](state, { noteId, discussionId, suggestionId }) {
  167. const noteObj = utils.findNoteObjectById(state.discussions, discussionId);
  168. const comment = utils.findNoteObjectById(noteObj.notes, noteId);
  169. comment.suggestions = comment.suggestions.map(suggestion => ({
  170. ...suggestion,
  171. applied: suggestion.applied || suggestion.id === suggestionId,
  172. appliable: false,
  173. }));
  174. },
  175. [types.UPDATE_DISCUSSION](state, noteData) {
  176. const note = noteData;
  177. const selectedDiscussion = state.discussions.find(disc => disc.id === note.id);
  178. note.expanded = true; // override expand flag to prevent collapse
  179. if (note.diff_file) {
  180. Object.assign(note, {
  181. file_hash: note.diff_file.file_hash,
  182. });
  183. }
  184. Object.assign(selectedDiscussion, { ...note });
  185. },
  186. [types.CLOSE_ISSUE](state) {
  187. Object.assign(state.noteableData, { state: constants.CLOSED });
  188. },
  189. [types.REOPEN_ISSUE](state) {
  190. Object.assign(state.noteableData, { state: constants.REOPENED });
  191. },
  192. [types.TOGGLE_STATE_BUTTON_LOADING](state, value) {
  193. Object.assign(state, { isToggleStateButtonLoading: value });
  194. },
  195. [types.SET_NOTES_FETCHED_STATE](state, value) {
  196. Object.assign(state, { isNotesFetched: value });
  197. },
  198. [types.SET_NOTES_LOADING_STATE](state, value) {
  199. state.isLoading = value;
  200. },
  201. [types.SET_DISCUSSION_DIFF_LINES](state, { discussionId, diffLines }) {
  202. const discussion = utils.findNoteObjectById(state.discussions, discussionId);
  203. discussion.truncated_diff_lines = diffLines;
  204. },
  205. [types.DISABLE_COMMENTS](state, value) {
  206. state.commentsDisabled = value;
  207. },
  208. [types.UPDATE_RESOLVABLE_DISCUSSIONS_COUNTS](state) {
  209. state.resolvableDiscussionsCount = state.discussions.filter(
  210. discussion => !discussion.individual_note && discussion.resolvable,
  211. ).length;
  212. state.unresolvedDiscussionsCount = state.discussions.filter(
  213. discussion =>
  214. !discussion.individual_note &&
  215. discussion.resolvable &&
  216. discussion.notes.some(note => note.resolvable && !note.resolved),
  217. ).length;
  218. state.hasUnresolvedDiscussions = state.unresolvedDiscussionsCount > 1;
  219. },
  220. };