summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/notes
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/notes')
-rw-r--r--app/assets/javascripts/notes/components/comment_form.vue2
-rw-r--r--app/assets/javascripts/notes/components/diff_file_header.vue2
-rw-r--r--app/assets/javascripts/notes/components/diff_with_note.vue7
-rw-r--r--app/assets/javascripts/notes/components/note_actions.vue19
-rw-r--r--app/assets/javascripts/notes/components/note_awards_list.vue4
-rw-r--r--app/assets/javascripts/notes/components/note_form.vue13
-rw-r--r--app/assets/javascripts/notes/components/note_header.vue13
-rw-r--r--app/assets/javascripts/notes/components/noteable_discussion.vue21
-rw-r--r--app/assets/javascripts/notes/components/noteable_note.vue1
-rw-r--r--app/assets/javascripts/notes/components/notes_app.vue7
-rw-r--r--app/assets/javascripts/notes/stores/actions.js68
-rw-r--r--app/assets/javascripts/notes/stores/getters.js14
-rw-r--r--app/assets/javascripts/notes/stores/index.js12
-rw-r--r--app/assets/javascripts/notes/stores/modules/index.js4
-rw-r--r--app/assets/javascripts/notes/stores/mutations.js40
-rw-r--r--app/assets/javascripts/notes/stores/utils.js21
16 files changed, 133 insertions, 115 deletions
diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue
index 6612bc44e0b..7735133c470 100644
--- a/app/assets/javascripts/notes/components/comment_form.vue
+++ b/app/assets/javascripts/notes/components/comment_form.vue
@@ -374,7 +374,7 @@ js-gfm-input js-autosize markdown-area js-vue-textarea"
append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown">
<button
:disabled="isSubmitButtonDisabled"
- class="btn btn-create comment-btn js-comment-button js-comment-submit-button"
+ class="btn btn-success comment-btn js-comment-button js-comment-submit-button"
type="submit"
@click.prevent="handleSave()">
{{ __(commentButtonTitle) }}
diff --git a/app/assets/javascripts/notes/components/diff_file_header.vue b/app/assets/javascripts/notes/components/diff_file_header.vue
index fc7b52be241..4fd93304a03 100644
--- a/app/assets/javascripts/notes/components/diff_file_header.vue
+++ b/app/assets/javascripts/notes/components/diff_file_header.vue
@@ -41,8 +41,8 @@ export default {
</div>
<template v-else>
<component
- ref="titleWrapper"
:is="titleTag"
+ ref="titleWrapper"
:href="diffFile.discussionPath"
>
<span v-html="diffFile.blobIcon"></span>
diff --git a/app/assets/javascripts/notes/components/diff_with_note.vue b/app/assets/javascripts/notes/components/diff_with_note.vue
index 27ff7dea909..802be022ba6 100644
--- a/app/assets/javascripts/notes/components/diff_with_note.vue
+++ b/app/assets/javascripts/notes/components/diff_with_note.vue
@@ -148,10 +148,9 @@ export default {
</tr>
<tr class="notes_holder">
<td
- class="notes_line"
- colspan="2"
- ></td>
- <td class="notes_content">
+ class="notes_content"
+ colspan="3"
+ >
<slot></slot>
</td>
</tr>
diff --git a/app/assets/javascripts/notes/components/note_actions.vue b/app/assets/javascripts/notes/components/note_actions.vue
index cdbbb342331..beb53da0e6d 100644
--- a/app/assets/javascripts/notes/components/note_actions.vue
+++ b/app/assets/javascripts/notes/components/note_actions.vue
@@ -7,7 +7,6 @@ import editSvg from 'icons/_icon_pencil.svg';
import resolveDiscussionSvg from 'icons/_icon_resolve_discussion.svg';
import resolvedDiscussionSvg from 'icons/_icon_status_success_solid.svg';
import ellipsisSvg from 'icons/_ellipsis_v.svg';
-import loadingIcon from '~/vue_shared/components/loading_icon.vue';
import tooltip from '~/vue_shared/directives/tooltip';
export default {
@@ -15,21 +14,19 @@ export default {
directives: {
tooltip,
},
- components: {
- loadingIcon,
- },
props: {
authorId: {
type: Number,
required: true,
},
noteId: {
- type: Number,
+ type: String,
required: true,
},
noteUrl: {
type: String,
- required: true,
+ required: false,
+ default: '',
},
accessLevel: {
type: String,
@@ -152,9 +149,9 @@ export default {
v-else
v-html="resolveDiscussionSvg"></div>
</template>
- <loading-icon
+ <gl-loading-icon
v-else
- :inline="true"
+ inline
/>
</button>
</div>
@@ -171,7 +168,7 @@ export default {
href="#"
title="Add reaction"
>
- <loading-icon :inline="true" />
+ <gl-loading-icon inline/>
<span
class="link-highlight award-control-icon-neutral"
v-html="emojiSmiling">
@@ -225,11 +222,11 @@ export default {
Report as abuse
</a>
</li>
- <li>
+ <li v-if="noteUrl">
<button
:data-clipboard-text="noteUrl"
type="button"
- css-class="btn-default btn-transparent"
+ class="btn-default btn-transparent js-btn-copy-note-link"
>
Copy link
</button>
diff --git a/app/assets/javascripts/notes/components/note_awards_list.vue b/app/assets/javascripts/notes/components/note_awards_list.vue
index e111d3b9ac2..c68860d98ae 100644
--- a/app/assets/javascripts/notes/components/note_awards_list.vue
+++ b/app/assets/javascripts/notes/components/note_awards_list.vue
@@ -25,7 +25,7 @@ export default {
required: true,
},
noteId: {
- type: Number,
+ type: String,
required: true,
},
canAwardEmoji: {
@@ -182,9 +182,9 @@ export default {
<div class="note-awards">
<div class="awards js-awards-block">
<button
- v-tooltip
v-for="(awardList, awardName, index) in groupedAwards"
:key="index"
+ v-tooltip
:class="getAwardClassBindings(awardList)"
:title="awardTitle(awardList)"
class="btn award-control"
diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue
index abcd4422d7c..2d47d55f33c 100644
--- a/app/assets/javascripts/notes/components/note_form.vue
+++ b/app/assets/javascripts/notes/components/note_form.vue
@@ -20,9 +20,9 @@ export default {
default: '',
},
noteId: {
- type: Number,
+ type: String,
required: false,
- default: 0,
+ default: '',
},
markdownVersion: {
type: Number,
@@ -67,7 +67,10 @@ export default {
'getUserDataByProp',
]),
noteHash() {
- return `#note_${this.noteId}`;
+ if (this.noteId) {
+ return `#note_${this.noteId}`;
+ }
+ return '#';
},
markdownPreviewPath() {
return this.getNoteableDataByProp('preview_note_path');
@@ -168,8 +171,8 @@ export default {
id="note_note"
ref="textarea"
slot="textarea"
- :data-supports-quick-actions="!isEditing"
v-model="updatedNoteBody"
+ :data-supports-quick-actions="!isEditing"
name="note[note]"
class="note-textarea js-gfm-input js-note-text
js-autosize markdown-area js-vue-issue-note-form js-vue-textarea"
@@ -185,7 +188,7 @@ js-autosize markdown-area js-vue-issue-note-form js-vue-textarea"
<button
:disabled="isDisabled"
type="button"
- class="js-vue-issue-save btn btn-save js-comment-button "
+ class="js-vue-issue-save btn btn-success js-comment-button "
@click="handleUpdate()">
{{ saveButtonTitle }}
</button>
diff --git a/app/assets/javascripts/notes/components/note_header.vue b/app/assets/javascripts/notes/components/note_header.vue
index a621418cf72..d669d12a39b 100644
--- a/app/assets/javascripts/notes/components/note_header.vue
+++ b/app/assets/javascripts/notes/components/note_header.vue
@@ -9,7 +9,8 @@ export default {
props: {
author: {
type: Object,
- required: true,
+ required: false,
+ default: () => ({}),
},
createdAt: {
type: String,
@@ -21,7 +22,7 @@ export default {
default: '',
},
noteId: {
- type: Number,
+ type: String,
required: true,
},
includeToggle: {
@@ -72,7 +73,10 @@ export default {
{{ __('Toggle discussion') }}
</button>
</div>
- <a :href="author.path">
+ <a
+ v-if="Object.keys(author).length"
+ :href="author.path"
+ >
<span class="note-header-author-name">{{ author.name }}</span>
<span
v-if="author.status_tooltip_html"
@@ -81,6 +85,9 @@ export default {
@{{ author.username }}
</span>
</a>
+ <span v-else>
+ {{ __('A deleted user') }}
+ </span>
<span class="note-headline-light">
<span class="note-headline-meta">
<template v-if="actionText">
diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue
index 0fe1c16854a..6ede7562edf 100644
--- a/app/assets/javascripts/notes/components/noteable_discussion.vue
+++ b/app/assets/javascripts/notes/components/noteable_discussion.vue
@@ -137,8 +137,10 @@ export default {
return this.unresolvedDiscussions.length > 1;
},
showJumpToNextDiscussion() {
- return this.hasMultipleUnresolvedDiscussions &&
- !this.isLastUnresolvedDiscussion(this.discussion.id, this.discussionsByDiffOrder);
+ return (
+ this.hasMultipleUnresolvedDiscussions &&
+ !this.isLastUnresolvedDiscussion(this.discussion.id, this.discussionsByDiffOrder)
+ );
},
shouldRenderDiffs() {
const { diffDiscussion, diffFile } = this.transformedDiscussion;
@@ -256,11 +258,16 @@ Please check your network connection and try again.`;
});
},
jumpToNextDiscussion() {
- const nextId =
- this.nextUnresolvedDiscussionId(this.discussion.id, this.discussionsByDiffOrder);
+ const nextId = this.nextUnresolvedDiscussionId(
+ this.discussion.id,
+ this.discussionsByDiffOrder,
+ );
this.jumpToDiscussion(nextId);
},
+ deleteNoteHandler(note) {
+ this.$emit('noteDeleted', this.discussion, note);
+ },
},
};
</script>
@@ -270,6 +277,7 @@ Please check your network connection and try again.`;
<div class="timeline-entry-inner">
<div class="timeline-icon">
<user-avatar-link
+ v-if="author"
:link-href="author.path"
:img-src="author.avatar_url"
:img-alt="author.name"
@@ -340,10 +348,11 @@ Please check your network connection and try again.`;
<div class="discussion-notes">
<ul class="notes">
<component
- v-for="note in discussion.notes"
:is="componentName(note)"
- :note="componentData(note)"
+ v-for="note in discussion.notes"
:key="note.id"
+ :note="componentData(note)"
+ @handleDeleteNote="deleteNoteHandler"
/>
</ul>
<div
diff --git a/app/assets/javascripts/notes/components/noteable_note.vue b/app/assets/javascripts/notes/components/noteable_note.vue
index 4ebeb5599f2..7579fc852c6 100644
--- a/app/assets/javascripts/notes/components/noteable_note.vue
+++ b/app/assets/javascripts/notes/components/noteable_note.vue
@@ -86,6 +86,7 @@ export default {
// eslint-disable-next-line no-alert
if (window.confirm('Are you sure you want to delete this comment?')) {
this.isDeleting = true;
+ this.$emit('handleDeleteNote', this.note);
this.deleteNote(this.note)
.then(() => {
diff --git a/app/assets/javascripts/notes/components/notes_app.vue b/app/assets/javascripts/notes/components/notes_app.vue
index 9b8713b40fb..d8e8efb982a 100644
--- a/app/assets/javascripts/notes/components/notes_app.vue
+++ b/app/assets/javascripts/notes/components/notes_app.vue
@@ -10,7 +10,6 @@ import systemNote from '../../vue_shared/components/notes/system_note.vue';
import commentForm from './comment_form.vue';
import placeholderNote from '../../vue_shared/components/notes/placeholder_note.vue';
import placeholderSystemNote from '../../vue_shared/components/notes/placeholder_system_note.vue';
-import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import skeletonLoadingContainer from '../../vue_shared/components/notes/skeleton_note.vue';
export default {
@@ -20,7 +19,6 @@ export default {
noteableDiscussion,
systemNote,
commentForm,
- loadingIcon,
placeholderNote,
placeholderSystemNote,
},
@@ -138,6 +136,7 @@ export default {
.then(() => {
this.isLoading = false;
this.setNotesFetchedState(true);
+ eventHub.$emit('fetchedNotesData');
})
.then(() => this.$nextTick())
.then(() => this.checkLocationHash())
@@ -188,10 +187,10 @@ export default {
class="notes main-notes-list timeline"
>
<component
- v-for="discussion in allDiscussions"
:is="getComponentName(discussion)"
- v-bind="getComponentData(discussion)"
+ v-for="discussion in allDiscussions"
:key="discussion.id"
+ v-bind="getComponentData(discussion)"
/>
</ul>
diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js
index 3eefbe11c37..320dfa47d5a 100644
--- a/app/assets/javascripts/notes/stores/actions.js
+++ b/app/assets/javascripts/notes/stores/actions.js
@@ -10,6 +10,7 @@ import service from '../services/notes_service';
import loadAwardsHandler from '../../awards_handler';
import sidebarTimeTrackingEventHub from '../../sidebar/event_hub';
import { isInViewport, scrollToElement } from '../../lib/utils/common_utils';
+import mrWidgetEventHub from '../../vue_merge_request_widget/event_hub';
let eTagPoll;
@@ -43,18 +44,17 @@ export const fetchDiscussions = ({ commit }, path) =>
commit(types.SET_INITIAL_DISCUSSIONS, discussions);
});
-export const refetchDiscussionById = ({ commit }, { path, discussionId }) =>
- service
- .fetchDiscussions(path)
- .then(res => res.json())
- .then(discussions => {
- const selectedDiscussion = discussions.find(discussion => discussion.id === discussionId);
- if (selectedDiscussion) commit(types.UPDATE_DISCUSSION, selectedDiscussion);
- });
+export const updateDiscussion = ({ commit, state }, discussion) => {
+ commit(types.UPDATE_DISCUSSION, discussion);
-export const deleteNote = ({ commit }, note) =>
+ return utils.findNoteObjectById(state.discussions, discussion.id);
+};
+
+export const deleteNote = ({ commit, dispatch }, note) =>
service.deleteNote(note.path).then(() => {
commit(types.DELETE_NOTE, note);
+
+ dispatch('updateMergeRequestWidget');
});
export const updateNote = ({ commit }, { endpoint, note }) =>
@@ -75,20 +75,22 @@ export const replyToDiscussion = ({ commit }, { endpoint, data }) =>
return res;
});
-export const createNewNote = ({ commit }, { endpoint, data }) =>
+export const createNewNote = ({ commit, dispatch }, { endpoint, data }) =>
service
.createNewNote(endpoint, data)
.then(res => res.json())
.then(res => {
if (!res.errors) {
commit(types.ADD_NEW_NOTE, res);
+
+ dispatch('updateMergeRequestWidget');
}
return res;
});
export const removePlaceholderNotes = ({ commit }) => commit(types.REMOVE_PLACEHOLDER_NOTES);
-export const toggleResolveNote = ({ commit }, { endpoint, isResolved, discussion }) =>
+export const toggleResolveNote = ({ commit, dispatch }, { endpoint, isResolved, discussion }) =>
service
.toggleResolveNote(endpoint, isResolved)
.then(res => res.json())
@@ -96,6 +98,8 @@ export const toggleResolveNote = ({ commit }, { endpoint, isResolved, discussion
const mutationType = discussion ? types.UPDATE_DISCUSSION : types.UPDATE_NOTE;
commit(mutationType, res);
+
+ dispatch('updateMergeRequestWidget');
});
export const closeIssue = ({ commit, dispatch, state }) => {
@@ -152,26 +156,28 @@ export const saveNote = ({ commit, dispatch }, noteData) => {
const replyId = noteData.data.in_reply_to_discussion_id;
const methodToDispatch = replyId ? 'replyToDiscussion' : 'createNewNote';
- commit(types.REMOVE_PLACEHOLDER_NOTES); // remove previous placeholders
$('.notes-form .flash-container').hide(); // hide previous flash notification
+ commit(types.REMOVE_PLACEHOLDER_NOTES); // remove previous placeholders
- if (hasQuickActions) {
- placeholderText = utils.stripQuickActions(placeholderText);
- }
+ if (replyId) {
+ if (hasQuickActions) {
+ placeholderText = utils.stripQuickActions(placeholderText);
+ }
- if (placeholderText.length) {
- commit(types.SHOW_PLACEHOLDER_NOTE, {
- noteBody: placeholderText,
- replyId,
- });
- }
+ if (placeholderText.length) {
+ commit(types.SHOW_PLACEHOLDER_NOTE, {
+ noteBody: placeholderText,
+ replyId,
+ });
+ }
- if (hasQuickActions) {
- commit(types.SHOW_PLACEHOLDER_NOTE, {
- isSystemNote: true,
- noteBody: utils.getQuickActionText(note),
- replyId,
- });
+ if (hasQuickActions) {
+ commit(types.SHOW_PLACEHOLDER_NOTE, {
+ isSystemNote: true,
+ noteBody: utils.getQuickActionText(note),
+ replyId,
+ });
+ }
}
return dispatch(methodToDispatch, noteData).then(res => {
@@ -211,7 +217,9 @@ export const saveNote = ({ commit, dispatch }, noteData) => {
if (errors && errors.commands_only) {
Flash(errors.commands_only, 'notice', noteData.flashContainer);
}
- commit(types.REMOVE_PLACEHOLDER_NOTES);
+ if (replyId) {
+ commit(types.REMOVE_PLACEHOLDER_NOTES);
+ }
return res;
});
@@ -320,5 +328,9 @@ export const fetchDiscussionDiffLines = ({ commit }, discussion) =>
});
});
+export const updateMergeRequestWidget = () => {
+ mrWidgetEventHub.$emit('mr.discussion.updated');
+};
+
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};
diff --git a/app/assets/javascripts/notes/stores/getters.js b/app/assets/javascripts/notes/stores/getters.js
index 5b3b9f8776f..d4babf1fab2 100644
--- a/app/assets/javascripts/notes/stores/getters.js
+++ b/app/assets/javascripts/notes/stores/getters.js
@@ -1,5 +1,6 @@
import _ from 'underscore';
import * as constants from '../constants';
+import { reduceDiscussionsToLineCodes } from './utils';
import { collapseSystemNotes } from './collapse_utils';
export const discussions = state => collapseSystemNotes(state.discussions);
@@ -28,17 +29,8 @@ export const notesById = state =>
return acc;
}, {});
-export const discussionsByLineCode = state =>
- state.discussions.reduce((acc, note) => {
- if (note.diff_discussion && note.line_code && note.resolvable) {
- // For context about line notes: there might be multiple notes with the same line code
- const items = acc[note.line_code] || [];
- items.push(note);
-
- Object.assign(acc, { [note.line_code]: items });
- }
- return acc;
- }, {});
+export const discussionsStructuredByLineCode = state =>
+ reduceDiscussionsToLineCodes(state.discussions);
export const noteableType = state => {
const { ISSUE_NOTEABLE_TYPE, MERGE_REQUEST_NOTEABLE_TYPE, EPIC_NOTEABLE_TYPE } = constants;
diff --git a/app/assets/javascripts/notes/stores/index.js b/app/assets/javascripts/notes/stores/index.js
index 0f48b8880f4..f105b7d0d11 100644
--- a/app/assets/javascripts/notes/stores/index.js
+++ b/app/assets/javascripts/notes/stores/index.js
@@ -1,16 +1,8 @@
import Vue from 'vue';
import Vuex from 'vuex';
-import * as actions from './actions';
-import * as getters from './getters';
-import mutations from './mutations';
-import module from './modules';
+import notesModule from './modules';
Vue.use(Vuex);
export default () =>
- new Vuex.Store({
- state: module.state,
- actions,
- getters,
- mutations,
- });
+ new Vuex.Store(notesModule());
diff --git a/app/assets/javascripts/notes/stores/modules/index.js b/app/assets/javascripts/notes/stores/modules/index.js
index b4cb9267e0f..61dbb075586 100644
--- a/app/assets/javascripts/notes/stores/modules/index.js
+++ b/app/assets/javascripts/notes/stores/modules/index.js
@@ -2,7 +2,7 @@ import * as actions from '../actions';
import * as getters from '../getters';
import mutations from '../mutations';
-export default {
+export default () => ({
state: {
discussions: [],
targetNoteHash: null,
@@ -24,4 +24,4 @@ export default {
actions,
getters,
mutations,
-};
+});
diff --git a/app/assets/javascripts/notes/stores/mutations.js b/app/assets/javascripts/notes/stores/mutations.js
index ab6a95e2601..73e55705f39 100644
--- a/app/assets/javascripts/notes/stores/mutations.js
+++ b/app/assets/javascripts/notes/stores/mutations.js
@@ -4,7 +4,8 @@ import * as constants from '../constants';
import { isInMRPage } from '../../lib/utils/common_utils';
export default {
- [types.ADD_NEW_NOTE](state, note) {
+ [types.ADD_NEW_NOTE](state, data) {
+ const note = data.discussion ? data.discussion.notes[0] : data;
const { discussion_id, type } = note;
const [exists] = state.discussions.filter(n => n.id === note.discussion_id);
const isDiscussion = type === constants.DISCUSSION_NOTE || type === constants.DIFF_NOTE;
@@ -54,13 +55,12 @@ export default {
[types.EXPAND_DISCUSSION](state, { discussionId }) {
const discussion = utils.findNoteObjectById(state.discussions, discussionId);
-
- discussion.expanded = true;
+ Object.assign(discussion, { expanded: true });
},
[types.COLLAPSE_DISCUSSION](state, { discussionId }) {
const discussion = utils.findNoteObjectById(state.discussions, discussionId);
- discussion.expanded = false;
+ Object.assign(discussion, { expanded: false });
},
[types.REMOVE_PLACEHOLDER_NOTES](state) {
@@ -95,10 +95,18 @@ export default {
[types.SET_USER_DATA](state, data) {
Object.assign(state, { userData: data });
},
+
[types.SET_INITIAL_DISCUSSIONS](state, discussionsData) {
const discussions = [];
discussionsData.forEach(discussion => {
+ if (discussion.diff_file) {
+ Object.assign(discussion, {
+ fileHash: discussion.diff_file.file_hash,
+ truncated_diff_lines: discussion.truncated_diff_lines || [],
+ });
+ }
+
// To support legacy notes, should be very rare case.
if (discussion.individual_note && discussion.notes.length > 1) {
discussion.notes.forEach(n => {
@@ -168,8 +176,7 @@ export default {
[types.TOGGLE_DISCUSSION](state, { discussionId }) {
const discussion = utils.findNoteObjectById(state.discussions, discussionId);
-
- discussion.expanded = !discussion.expanded;
+ Object.assign(discussion, { expanded: !discussion.expanded });
},
[types.UPDATE_NOTE](state, note) {
@@ -185,16 +192,12 @@ export default {
[types.UPDATE_DISCUSSION](state, noteData) {
const note = noteData;
- let index = 0;
-
- state.discussions.forEach((n, i) => {
- if (n.id === note.id) {
- index = i;
- }
- });
-
+ const selectedDiscussion = state.discussions.find(disc => disc.id === note.id);
note.expanded = true; // override expand flag to prevent collapse
- state.discussions.splice(index, 1, note);
+ if (note.diff_file) {
+ Object.assign(note, { fileHash: note.diff_file.file_hash });
+ }
+ Object.assign(selectedDiscussion, { ...note });
},
[types.CLOSE_ISSUE](state) {
@@ -215,12 +218,7 @@ export default {
[types.SET_DISCUSSION_DIFF_LINES](state, { discussionId, diffLines }) {
const discussion = utils.findNoteObjectById(state.discussions, discussionId);
- const index = state.discussions.indexOf(discussion);
-
- const discussionWithDiffLines = Object.assign({}, discussion, {
- truncated_diff_lines: diffLines,
- });
- state.discussions.splice(index, 1, discussionWithDiffLines);
+ discussion.truncated_diff_lines = diffLines;
},
};
diff --git a/app/assets/javascripts/notes/stores/utils.js b/app/assets/javascripts/notes/stores/utils.js
index a0e096ebfaf..0e41ff03d67 100644
--- a/app/assets/javascripts/notes/stores/utils.js
+++ b/app/assets/javascripts/notes/stores/utils.js
@@ -2,13 +2,11 @@ import AjaxCache from '~/lib/utils/ajax_cache';
const REGEX_QUICK_ACTIONS = /^\/\w+.*$/gm;
-export const findNoteObjectById = (notes, id) =>
- notes.filter(n => n.id === id)[0];
+export const findNoteObjectById = (notes, id) => notes.filter(n => n.id === id)[0];
export const getQuickActionText = note => {
let text = 'Applying command';
- const quickActions =
- AjaxCache.get(gl.GfmAutoComplete.dataSources.commands) || [];
+ const quickActions = AjaxCache.get(gl.GfmAutoComplete.dataSources.commands) || [];
const executedCommands = quickActions.filter(command => {
const commandRegex = new RegExp(`/${command.name}`);
@@ -27,7 +25,18 @@ export const getQuickActionText = note => {
return text;
};
+export const reduceDiscussionsToLineCodes = selectedDiscussions =>
+ selectedDiscussions.reduce((acc, note) => {
+ if (note.diff_discussion && note.line_code) {
+ // For context about line notes: there might be multiple notes with the same line code
+ const items = acc[note.line_code] || [];
+ items.push(note);
+
+ Object.assign(acc, { [note.line_code]: items });
+ }
+ return acc;
+ }, {});
+
export const hasQuickActions = note => REGEX_QUICK_ACTIONS.test(note);
-export const stripQuickActions = note =>
- note.replace(REGEX_QUICK_ACTIONS, '').trim();
+export const stripQuickActions = note => note.replace(REGEX_QUICK_ACTIONS, '').trim();