diff options
author | Filipa Lacerda <filipa@gitlab.com> | 2017-07-26 12:02:01 +0100 |
---|---|---|
committer | Filipa Lacerda <filipa@gitlab.com> | 2017-07-26 12:02:01 +0100 |
commit | ffef16690c61581e3254dd074e55b58dc4d2b7bb (patch) | |
tree | 4cd9a6de5b1513d4d71a5eb290a4bafd17c743b5 | |
parent | 4e81ad2ab9eb0190527514cd8b7cef44df4a9bfc (diff) | |
download | gitlab-ce-ffef16690c61581e3254dd074e55b58dc4d2b7bb.tar.gz |
Use mapActions, mapGetters and mapMutations for components
16 files changed, 850 insertions, 804 deletions
diff --git a/app/assets/javascripts/notes/components/issue_comment_form.vue b/app/assets/javascripts/notes/components/issue_comment_form.vue index c913f3f5fad..bd6caddb40f 100644 --- a/app/assets/javascripts/notes/components/issue_comment_form.vue +++ b/app/assets/javascripts/notes/components/issue_comment_form.vue @@ -1,6 +1,7 @@ <script> /* global Flash */ + import { mapActions } from 'vuex'; import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue'; import markdownField from '../../vue_shared/components/markdown/field.vue'; import issueNoteSignedOutWidget from './issue_note_signed_out_widget.vue'; @@ -60,6 +61,9 @@ }, }, methods: { + ...mapActions([ + 'saveNote' + ]), handleSave(withIssueAction) { if (this.note.length) { const noteData = { @@ -79,7 +83,7 @@ noteData.data.note.type = constants.DISCUSSION_NOTE; } - this.$store.dispatch('saveNote', noteData) + this.saveNote(noteData) .then((res) => { if (res.errors) { if (res.errors.commands_only) { diff --git a/app/assets/javascripts/notes/components/issue_discussion.vue b/app/assets/javascripts/notes/components/issue_discussion.vue index 7fc4a41fa8a..21b5b288121 100644 --- a/app/assets/javascripts/notes/components/issue_discussion.vue +++ b/app/assets/javascripts/notes/components/issue_discussion.vue @@ -1,108 +1,112 @@ <script> -/* global Flash */ + /* global Flash */ + import { mapActions } from 'vuex'; + import { TOGGLE_DISCUSSION } from '../stores/mutation_types'; + import { SYSTEM_NOTE } from '../constants'; + import issueNote from './issue_note.vue'; + import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue'; + import issueNoteHeader from './issue_note_header.vue'; + import issueNoteActions from './issue_note_actions.vue'; + import issueNoteSignedOutWidget from './issue_note_signed_out_widget.vue'; + import issueNoteEditedText from './issue_note_edited_text.vue'; + import issueNoteForm from './issue_note_form.vue'; + import placeholderNote from './issue_placeholder_note.vue'; + import placeholderSystemNote from './issue_placeholder_system_note.vue'; -import issueNote from './issue_note.vue'; -import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue'; -import issueNoteHeader from './issue_note_header.vue'; -import issueNoteActions from './issue_note_actions.vue'; -import issueNoteSignedOutWidget from './issue_note_signed_out_widget.vue'; -import issueNoteEditedText from './issue_note_edited_text.vue'; -import issueNoteForm from './issue_note_form.vue'; -import placeholderNote from './issue_placeholder_note.vue'; -import placeholderSystemNote from './issue_placeholder_system_note.vue'; - -export default { - props: { - note: { - type: Object, - required: true, + export default { + props: { + note: { + type: Object, + required: true, + }, }, - }, - data() { - return { - newNotePath: window.gl.issueData.create_note_path, - isReplying: false, - }; - }, - components: { - issueNote, - userAvatarLink, - issueNoteHeader, - issueNoteActions, - issueNoteSignedOutWidget, - issueNoteEditedText, - issueNoteForm, - placeholderNote, - placeholderSystemNote, - }, - computed: { - discussion() { - return this.note.notes[0]; + data() { + return { + newNotePath: window.gl.issueData.create_note_path, + isReplying: false, + }; }, - author() { - return this.discussion.author; + components: { + issueNote, + userAvatarLink, + issueNoteHeader, + issueNoteActions, + issueNoteSignedOutWidget, + issueNoteEditedText, + issueNoteForm, + placeholderNote, + placeholderSystemNote, }, - canReply() { - return window.gl.issueData.current_user.can_create_note; + computed: { + discussion() { + return this.note.notes[0]; + }, + author() { + return this.discussion.author; + }, + canReply() { + return window.gl.issueData.current_user.can_create_note; + }, }, - }, - methods: { - componentName(note) { - if (note.isPlaceholderNote) { - if (note.placeholderType === 'systemNote') { - return placeholderSystemNote; + methods: { + ...mapActions([ + 'saveNote', + ]), + ...mapMutations({ + toggleDiscussion: TOGGLE_DISCUSSION, + }), + componentName(note) { + if (note.isPlaceholderNote) { + if (note.placeholderType === SYSTEM_NOTE) { + return placeholderSystemNote; + } + return placeholderNote; } - return placeholderNote; - } - return issueNote; - }, - componentData(note) { - return note.isPlaceholderNote ? note.notes[0] : note; - }, - toggleDiscussion() { - this.$store.commit('toggleDiscussion', { - discussionId: this.note.id, - }); - }, - showReplyForm() { - this.isReplying = true; - }, - cancelReplyForm(shouldConfirm) { - if (shouldConfirm && this.$refs.noteForm.isDirty) { - const msg = 'Are you sure you want to cancel creating this comment?'; - // eslint-disable-next-line no-alert - const isConfirmed = confirm(msg); - if (!isConfirmed) { - return; + return issueNote; + }, + componentData(note) { + return note.isPlaceholderNote ? note.notes[0] : note; + }, + toggleDiscussion() { + this.toggleDiscussion({ discussionId: this.note.id }); + }, + showReplyForm() { + this.isReplying = true; + }, + cancelReplyForm(shouldConfirm) { + if (shouldConfirm && this.$refs.noteForm.isDirty) { + const msg = 'Are you sure you want to cancel creating this comment?'; + // eslint-disable-next-line no-alert + const isConfirmed = confirm(msg); + if (!isConfirmed) { + return; + } } - } - this.isReplying = false; - }, - saveReply({ note }) { - const replyData = { - endpoint: this.newNotePath, - flashContainer: this.$el, - data: { - in_reply_to_discussion_id: this.note.reply_id, - target_type: 'issue', - target_id: this.discussion.noteable_id, - note: { note }, - full_data: true, - }, - }; + this.isReplying = false; + }, + saveReply({ note }) { + const replyData = { + endpoint: this.newNotePath, + flashContainer: this.$el, + data: { + in_reply_to_discussion_id: this.note.reply_id, + target_type: 'issue', + target_id: this.discussion.noteable_id, + note: { note }, + full_data: true, + }, + }; - this.$store.dispatch('saveNote', replyData) - .then(() => { - this.isReplying = false; - }) - .catch(() => { - Flash('Something went wrong while adding your reply. Please try again.'); - }); + this.saveNote(replyData) + .then(() => { + this.isReplying = false; + }) + .catch(() => Flash('Something went wrong while adding your reply. Please try again.')); + }, }, - }, -}; + }; </script> <template> @@ -132,8 +136,7 @@ export default { :edited-at="note.last_updated_at" :edited-by="note.last_updated_by" actionText="Last updated" - className="discussion-headline-light js-discussion-headline" - /> + className="discussion-headline-light js-discussion-headline" /> </div> </div> <div @@ -162,7 +165,8 @@ export default { saveButtonTitle="Comment" :update-handler="saveReply" :cancel-handler="cancelReplyForm" - ref="noteForm" /> + ref="noteForm" + /> <issue-note-signed-out-widget v-if="!canReply" /> </div> </div> diff --git a/app/assets/javascripts/notes/components/issue_note.vue b/app/assets/javascripts/notes/components/issue_note.vue index 6514ec3b7ab..d490578ce6f 100644 --- a/app/assets/javascripts/notes/components/issue_note.vue +++ b/app/assets/javascripts/notes/components/issue_note.vue @@ -1,116 +1,118 @@ <script> -/* global Flash */ + /* global Flash */ -import { mapGetters } from 'vuex'; -import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue'; -import issueNoteHeader from './issue_note_header.vue'; -import issueNoteActions from './issue_note_actions.vue'; -import issueNoteBody from './issue_note_body.vue'; -import eventHub from '../event_hub'; + import { mapGetters, mapActions } from 'vuex'; + import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue'; + import issueNoteHeader from './issue_note_header.vue'; + import issueNoteActions from './issue_note_actions.vue'; + import issueNoteBody from './issue_note_body.vue'; + import eventHub from '../event_hub'; -export default { - props: { - note: { - type: Object, - required: true, + export default { + props: { + note: { + type: Object, + required: true, + }, }, - }, - data() { - return { - isEditing: false, - isDeleting: false, - }; - }, - components: { - userAvatarLink, - issueNoteHeader, - issueNoteActions, - issueNoteBody, - }, - computed: { - ...mapGetters([ - 'targetNoteHash', - ]), - author() { - return this.note.author; - }, - classNameBindings() { + data() { return { - 'is-editing': this.isEditing, - 'disabled-content': this.isDeleting, - 'js-my-note': this.author.id === window.gon.current_user_id, - target: this.targetNoteHash === this.noteAnchorId, + isEditing: false, + isDeleting: false, }; }, - canReportAsAbuse() { - return this.note.report_abuse_path && this.author.id !== window.gon.current_user_id; - }, - noteAnchorId() { - return `note_${this.note.id}`; + components: { + userAvatarLink, + issueNoteHeader, + issueNoteActions, + issueNoteBody, }, - }, - methods: { - editHandler() { - this.isEditing = true; + computed: { + ...mapGetters([ + 'targetNoteHash', + ]), + author() { + return this.note.author; + }, + classNameBindings() { + return { + 'is-editing': this.isEditing, + 'disabled-content': this.isDeleting, + 'js-my-note': this.author.id === window.gon.current_user_id, + target: this.targetNoteHash === this.noteAnchorId, + }; + }, + canReportAsAbuse() { + return this.note.report_abuse_path && this.author.id !== window.gon.current_user_id; + }, + noteAnchorId() { + return `note_${this.note.id}`; + }, }, - deleteHandler() { - const msg = 'Are you sure you want to delete this list?'; - const isConfirmed = confirm(msg); // eslint-disable-line + methods: { + ...mapActions([ + 'deleteNote', + 'updateNote', + 'scrollToNoteIfNeeded', + ]), + editHandler() { + this.isEditing = true; + }, + deleteHandler() { + const msg = 'Are you sure you want to delete this list?'; + const isConfirmed = confirm(msg); // eslint-disable-line + + if (isConfirmed) { + this.isDeleting = true; + this.deleteNote(this.note) + .then(() => { + this.isDeleting = false; + }) + .catch(() => { + Flash('Something went wrong while deleting your note. Please try again.'); + this.isDeleting = false; + }); + } + }, + formUpdateHandler(note) { + const data = { + endpoint: this.note.path, + note: { + full_data: true, + target_type: 'issue', + target_id: this.note.noteable_id, + note, + }, + }; - if (isConfirmed) { - this.isDeleting = true; - this.$store - .dispatch('deleteNote', this.note) + this.updateNote(data) .then(() => { - this.isDeleting = false; + this.isEditing = false; + $(this.$refs.noteBody.$el).renderGFM(); }) - .catch(() => { - new Flash('Something went wrong while deleting your note. Please try again.'); // eslint-disable-line - this.isDeleting = false; - }); - } - }, - formUpdateHandler(note) { - const data = { - endpoint: this.note.path, - note: { - full_data: true, - target_type: 'issue', - target_id: this.note.noteable_id, - note, - }, - }; + .catch(() => Flash('Something went wrong while editing your comment. Please try again.')); + }, + formCancelHandler(shouldConfirm) { + if (shouldConfirm && this.$refs.noteBody.$refs.noteForm.isDirty) { + const msg = 'Are you sure you want to cancel editing this comment?'; + const isConfirmed = confirm(msg); // eslint-disable-line + if (!isConfirmed) { + return; + } + } - this.$store.dispatch('updateNote', data) - .then(() => { - this.isEditing = false; - $(this.$refs.noteBody.$el).renderGFM(); - }) - .catch(() => { - Flash('Something went wrong while editing your comment. Please try again.'); - }); + this.isEditing = false; + }, }, - formCancelHandler(shouldConfirm) { - if (shouldConfirm && this.$refs.noteBody.$refs.noteForm.isDirty) { - const msg = 'Are you sure you want to cancel editing this comment?'; - const isConfirmed = confirm(msg); // eslint-disable-line - if (!isConfirmed) { - return; + created() { + eventHub.$on('enterEditMode', ({ noteId }) => { + if (noteId === this.note.id) { + this.isEditing = true; + this.scrollToNoteIfNeeded($(this.$el)); } - } - - this.isEditing = false; + }); }, - }, - created() { - eventHub.$on('enterEditMode', ({ noteId }) => { - if (noteId === this.note.id) { - this.isEditing = true; - this.$store.dispatch('scrollToNoteIfNeeded', $(this.$el)); - } - }); - }, -}; + }; </script> <template> @@ -124,7 +126,8 @@ export default { :link-href="author.path" :img-src="author.avatar_url" :img-alt="author.name" - :img-size="40" /> + :img-size="40" + /> </div> <div class="timeline-content"> <div class="note-header"> @@ -132,7 +135,8 @@ export default { :author="author" :created-at="note.created_at" :note-id="note.id" - actionText="commented" /> + actionText="commented" + /> <issue-note-actions :author-id="author.id" :note-id="note.id" @@ -142,7 +146,8 @@ export default { :can-report-as-abuse="canReportAsAbuse" :report-abuse-path="note.report_abuse_path" :edit-handler="editHandler" - :delete-handler="deleteHandler" /> + :delete-handler="deleteHandler" + /> </div> <issue-note-body :note="note" @@ -150,7 +155,8 @@ export default { :is-editing="isEditing" :form-update-handler="formUpdateHandler" :form-cancel-handler="formCancelHandler" - ref="noteBody" /> + ref="noteBody" + /> </div> </div> </li> diff --git a/app/assets/javascripts/notes/components/issue_note_actions.vue b/app/assets/javascripts/notes/components/issue_note_actions.vue index df5a060d894..6c63cae17cc 100644 --- a/app/assets/javascripts/notes/components/issue_note_actions.vue +++ b/app/assets/javascripts/notes/components/issue_note_actions.vue @@ -1,68 +1,71 @@ <script> -import emojiSmiling from 'icons/_emoji_slightly_smiling_face.svg'; -import emojiSmile from 'icons/_emoji_smile.svg'; -import emojiSmiley from 'icons/_emoji_smiley.svg'; -import loadingIcon from '../../vue_shared/components/loadingIcon.vue'; + import emojiSmiling from 'icons/_emoji_slightly_smiling_face.svg'; + import emojiSmile from 'icons/_emoji_smile.svg'; + import emojiSmiley from 'icons/_emoji_smiley.svg'; + import loadingIcon from '../../vue_shared/components/loading_icon.vue'; -export default { - props: { - authorId: { - type: Number, - required: true, + export default { + props: { + authorId: { + type: Number, + required: true, + }, + noteId: { + type: Number, + required: true, + }, + accessLevel: { + type: String, + required: false, + default: '', + }, + reportAbusePath: { + type: String, + required: true, + }, + canEdit: { + type: Boolean, + required: true, + }, + canDelete: { + type: Boolean, + required: true, + }, + canReportAsAbuse: { + type: Boolean, + required: true, + }, + editHandler: { + type: Function, + required: true, + }, + deleteHandler: { + type: Function, + required: true, + }, }, - noteId: { - type: Number, - required: true, + data() { + return { + emojiSmiling, + emojiSmile, + emojiSmiley, + }; }, - accessLevel: { - type: String, - required: false, - default: '', + components: { + loadingIcon, }, - reportAbusePath: { - type: String, - required: true, + computed: { + shouldShowActionsDropdown() { + return window.gon.current_user_id && (this.canEdit || this.canReportAsAbuse); + }, + canAddAwardEmoji() { + return window.gon.current_user_id; + }, + isAuthoredByMe() { + return this.authorId === window.gon.current_user_id; + }, }, - canEdit: { - type: Boolean, - required: true, - }, - canDelete: { - type: Boolean, - required: true, - }, - canReportAsAbuse: { - type: Boolean, - required: true, - }, - editHandler: { - type: Function, - required: true, - }, - deleteHandler: { - type: Function, - required: true, - }, - }, - data() { - return { - emojiSmiling, - emojiSmile, - emojiSmiley, - }; - }, - computed: { - shouldShowActionsDropdown() { - return window.gon.current_user_id && (this.canEdit || this.canReportAsAbuse); - }, - canAddAwardEmoji() { - return window.gon.current_user_id; - }, - isAuthoredByMe() { - return this.authorId === window.gon.current_user_id; - }, - }, -}; + }; </script> <template> @@ -82,13 +85,16 @@ export default { <loading-icon /> <span v-html="emojiSmiling" - class="link-highlight award-control-icon-neutral"></span> + class="link-highlight award-control-icon-neutral"> + </span> <span v-html="emojiSmiley" - class="link-highlight award-control-icon-positive"></span> + class="link-highlight award-control-icon-positive"> + </span> <span v-html="emojiSmile" - class="link-highlight award-control-icon-super-positive"></span> + class="link-highlight award-control-icon-super-positive"> + </span> </a> <div v-if="shouldShowActionsDropdown" @@ -101,7 +107,8 @@ export default { data-container="body"> <i aria-hidden="true" - class="fa fa-ellipsis-v icon"></i> + class="fa fa-ellipsis-v icon"> + </i> </button> <ul class="dropdown-menu more-actions-dropdown dropdown-open-left"> <template v-if="canEdit"> diff --git a/app/assets/javascripts/notes/components/issue_note_awards_list.vue b/app/assets/javascripts/notes/components/issue_note_awards_list.vue index c41c608979a..02c0aa0b9c4 100644 --- a/app/assets/javascripts/notes/components/issue_note_awards_list.vue +++ b/app/assets/javascripts/notes/components/issue_note_awards_list.vue @@ -1,164 +1,166 @@ <script> -/* global Flash */ - -import emojiSmiling from 'icons/_emoji_slightly_smiling_face.svg'; -import emojiSmile from 'icons/_emoji_smile.svg'; -import emojiSmiley from 'icons/_emoji_smiley.svg'; -import * as Emoji from '../../emoji'; - -export default { - props: { - awards: { - type: Array, - required: true, + /* global Flash */ + + import { mapActions } from 'vuex'; + import emojiSmiling from 'icons/_emoji_slightly_smiling_face.svg'; + import emojiSmile from 'icons/_emoji_smile.svg'; + import emojiSmiley from 'icons/_emoji_smiley.svg'; + import * as Emoji from '../../emoji'; + + export default { + props: { + awards: { + type: Array, + required: true, + }, + toggleAwardPath: { + type: String, + required: true, + }, + noteAuthorId: { + type: Number, + required: true, + }, + noteId: { + type: Number, + required: true, + }, }, - toggleAwardPath: { - type: String, - required: true, - }, - noteAuthorId: { - type: Number, - required: true, - }, - noteId: { - type: Number, - required: true, - }, - }, - data() { - const userId = window.gon.current_user_id; - - return { - emojiSmiling, - emojiSmile, - emojiSmiley, - canAward: !!userId, - myUserId: userId, - }; - }, - computed: { - // `this.awards` is an array with emojis but they are not grouped by emoji name. See below. - // [ { name: foo, user: user1 }, { name: bar, user: user1 }, { name: foo, user: user2 } ] - // This method will group emojis by their name as an Object. See below. - // { - // foo: [ { name: foo, user: user1 }, { name: foo, user: user2 } ], - // bar: [ { name: bar, user: user1 } ] - // } - // We need to do this otherwise we will render the same emoji over and over again. - groupedAwards() { - const awards = {}; - const orderedAwards = {}; - - this.awards.forEach((award) => { - awards[award.name] = awards[award.name] || []; - awards[award.name].push(award); - }); - - // Always show thumbsup and thumbsdown first - const { thumbsup, thumbsdown } = awards; - if (thumbsup) { - orderedAwards.thumbsup = thumbsup; - delete awards.thumbsup; - } - if (thumbsdown) { - orderedAwards.thumbsdown = thumbsdown; - delete awards.thumbsdown; - } - - // Because for-in forbidden - const keys = Object.keys(awards); - keys.forEach((key) => { - orderedAwards[key] = awards[key]; - }); - - return orderedAwards; - }, - isAuthoredByMe() { - return this.noteAuthorId === window.gon.current_user_id; - }, - }, - methods: { - getAwardHTML(name) { - return Emoji.glEmojiTag(name); - }, - getAwardClassBindings(awardList, awardName) { + data() { + const userId = window.gon.current_user_id; + return { - active: this.amIAwarded(awardList), - disabled: !this.canInteractWithEmoji(awardList, awardName), + emojiSmiling, + emojiSmile, + emojiSmiley, + canAward: !!userId, + myUserId: userId, }; }, - canInteractWithEmoji(awardList, awardName) { - let isAllowed = true; - const restrictedEmojis = ['thumbsup', 'thumbsdown']; - const { myUserId, noteAuthorId } = this; - - // Users can not add :+1: and :-1: to their notes - if (myUserId === noteAuthorId && restrictedEmojis.indexOf(awardName) > -1) { - isAllowed = false; - } + computed: { + // `this.awards` is an array with emojis but they are not grouped by emoji name. See below. + // [ { name: foo, user: user1 }, { name: bar, user: user1 }, { name: foo, user: user2 } ] + // This method will group emojis by their name as an Object. See below. + // { + // foo: [ { name: foo, user: user1 }, { name: foo, user: user2 } ], + // bar: [ { name: bar, user: user1 } ] + // } + // We need to do this otherwise we will render the same emoji over and over again. + groupedAwards() { + const awards = {}; + const orderedAwards = {}; + + this.awards.forEach((award) => { + awards[award.name] = awards[award.name] || []; + awards[award.name].push(award); + }); - return this.canAward && isAllowed; - }, - amIAwarded(awardList) { - const isAwarded = awardList.filter(award => award.user.id === this.myUserId); + // Always show thumbsup and thumbsdown first + const { thumbsup, thumbsdown } = awards; + if (thumbsup) { + orderedAwards.thumbsup = thumbsup; + delete awards.thumbsup; + } + if (thumbsdown) { + orderedAwards.thumbsdown = thumbsdown; + delete awards.thumbsdown; + } + + // Because for-in forbidden + const keys = Object.keys(awards); + keys.forEach((key) => { + orderedAwards[key] = awards[key]; + }); - return isAwarded.length; - }, - awardTitle(awardsList) { - const amIAwarded = this.amIAwarded(awardsList); - const TOOLTIP_NAME_COUNT = amIAwarded ? 9 : 10; - let awardList = awardsList; - - // Filter myself from list if I am awarded. - if (amIAwarded) { - awardList = awardList.filter(award => award.user.id !== this.myUserId); - } - - // Get only 9-10 usernames to show in tooltip text. - const namesToShow = awardList.slice(0, TOOLTIP_NAME_COUNT).map(award => award.user.name); - - // Get the remaining list to use in `and x more` text. - const remainingAwardList = awardList.slice(TOOLTIP_NAME_COUNT, awardList.length); - - // Add myself to the begining of the list so title will start with You. - if (amIAwarded) { - namesToShow.unshift('You'); - } - - let title = ''; - - // We have 10+ awarded user, join them with comma and add `and x more`. - if (remainingAwardList.length) { - title = `${namesToShow.join(', ')}, and ${remainingAwardList.length} more.`; - } else if (namesToShow.length > 1) { - // Join all names with comma but not the last one, it will be added with and text. - title = namesToShow.slice(0, namesToShow.length - 1).join(', '); - // If we have more than 2 users we need an extra comma before and text. - title += namesToShow.length > 2 ? ',' : ''; - title += ` and ${namesToShow.slice(-1)}`; // Append and text - } else { // We have only 2 users so join them with and. - title = namesToShow.join(' and '); - } - - return title; + return orderedAwards; + }, + isAuthoredByMe() { + return this.noteAuthorId === window.gon.current_user_id; + }, }, - handleAward(awardName) { - const data = { - endpoint: this.toggleAwardPath, - noteId: this.noteId, - awardName, - }; - - this.$store.dispatch('toggleAward', data) - .then(() => { - $(this.$el).find('.award-control').tooltip('fixTitle'); - }) - .catch(() => { - Flash('Something went wrong on our end.'); - }); + methods: { + ...mapActions([ + 'toggleAward', + ]), + getAwardHTML(name) { + return Emoji.glEmojiTag(name); + }, + getAwardClassBindings(awardList, awardName) { + return { + active: this.amIAwarded(awardList), + disabled: !this.canInteractWithEmoji(awardList, awardName), + }; + }, + canInteractWithEmoji(awardList, awardName) { + let isAllowed = true; + const restrictedEmojis = ['thumbsup', 'thumbsdown']; + const { myUserId, noteAuthorId } = this; + + // Users can not add :+1: and :-1: to their own notes + if (myUserId === noteAuthorId && restrictedEmojis.indexOf(awardName) > -1) { + isAllowed = false; + } + + return this.canAward && isAllowed; + }, + amIAwarded(awardList) { + const isAwarded = awardList.filter(award => award.user.id === this.myUserId); + + return isAwarded.length; + }, + awardTitle(awardsList) { + const amIAwarded = this.amIAwarded(awardsList); + const TOOLTIP_NAME_COUNT = amIAwarded ? 9 : 10; + let awardList = awardsList; + + // Filter myself from list if I am awarded. + if (amIAwarded) { + awardList = awardList.filter(award => award.user.id !== this.myUserId); + } + + // Get only 9-10 usernames to show in tooltip text. + const namesToShow = awardList.slice(0, TOOLTIP_NAME_COUNT).map(award => award.user.name); + + // Get the remaining list to use in `and x more` text. + const remainingAwardList = awardList.slice(TOOLTIP_NAME_COUNT, awardList.length); + + // Add myself to the begining of the list so title will start with You. + if (amIAwarded) { + namesToShow.unshift('You'); + } + + let title = ''; + + // We have 10+ awarded user, join them with comma and add `and x more`. + if (remainingAwardList.length) { + title = `${namesToShow.join(', ')}, and ${remainingAwardList.length} more.`; + } else if (namesToShow.length > 1) { + // Join all names with comma but not the last one, it will be added with and text. + title = namesToShow.slice(0, namesToShow.length - 1).join(', '); + // If we have more than 2 users we need an extra comma before and text. + title += namesToShow.length > 2 ? ',' : ''; + title += ` and ${namesToShow.slice(-1)}`; // Append and text + } else { // We have only 2 users so join them with and. + title = namesToShow.join(' and '); + } + + return title; + }, + handleAward(awardName) { + const data = { + endpoint: this.toggleAwardPath, + noteId: this.noteId, + awardName, + }; + + this.toggleAward(data) + .then(() => { + $(this.$el).find('.award-control').tooltip('fixTitle'); + }) + .catch(() => Flash('Something went wrong on our end.')); + }, }, - }, -}; + }; </script> <template> @@ -189,13 +191,16 @@ export default { type="button"> <span v-html="emojiSmiling" - class="award-control-icon award-control-icon-neutral"></span> + class="award-control-icon award-control-icon-neutral"> + </span> <span v-html="emojiSmiley" - class="award-control-icon award-control-icon-positive"></span> + class="award-control-icon award-control-icon-positive"> + </span> <span v-html="emojiSmile" - class="award-control-icon award-control-icon-super-positive"></span> + class="award-control-icon award-control-icon-super-positive"> + </span> <i aria-hidden="true" class="fa fa-spinner fa-spin award-control-icon award-control-icon-loading"></i> diff --git a/app/assets/javascripts/notes/components/issue_note_body.vue b/app/assets/javascripts/notes/components/issue_note_body.vue index 30c8db6f041..dee8bb0c7f9 100644 --- a/app/assets/javascripts/notes/components/issue_note_body.vue +++ b/app/assets/javascripts/notes/components/issue_note_body.vue @@ -1,70 +1,70 @@ <script> -import issueNoteEditedText from './issue_note_edited_text.vue'; -import issueNoteAwardsList from './issue_note_awards_list.vue'; -import issueNoteForm from './issue_note_form.vue'; -import TaskList from '../../task_list'; + import issueNoteEditedText from './issue_note_edited_text.vue'; + import issueNoteAwardsList from './issue_note_awards_list.vue'; + import issueNoteForm from './issue_note_form.vue'; + import TaskList from '../../task_list'; -export default { - props: { - note: { - type: Object, - required: true, + export default { + props: { + note: { + type: Object, + required: true, + }, + canEdit: { + type: Boolean, + required: true, + }, + isEditing: { + type: Boolean, + required: false, + default: false, + }, + formUpdateHandler: { + type: Function, + required: true, + }, + formCancelHandler: { + type: Function, + required: true, + }, }, - canEdit: { - type: Boolean, - required: true, + components: { + issueNoteEditedText, + issueNoteAwardsList, + issueNoteForm, }, - isEditing: { - type: Boolean, - required: false, - default: false, + computed: { + noteBody() { + return this.note.note; + }, }, - formUpdateHandler: { - type: Function, - required: true, - }, - formCancelHandler: { - type: Function, - required: true, - }, - }, - components: { - issueNoteEditedText, - issueNoteAwardsList, - issueNoteForm, - }, - computed: { - noteBody() { - return this.note.note; - }, - }, - methods: { - renderGFM() { - $(this.$refs['note-body']).renderGFM(); - }, - initTaskList() { - if (this.canEdit) { - this.taskList = new TaskList({ - dataType: 'note', - fieldName: 'note', - selector: '.notes', + methods: { + renderGFM() { + $(this.$refs['note-body']).renderGFM(); + }, + initTaskList() { + if (this.canEdit) { + this.taskList = new TaskList({ + dataType: 'note', + fieldName: 'note', + selector: '.notes', + }); + } + }, + handleFormUpdate() { + this.formUpdateHandler({ + note: this.$refs.noteForm.note, }); - } + }, + }, + mounted() { + this.renderGFM(); + this.initTaskList(); }, - handleFormUpdate() { - this.formUpdateHandler({ - note: this.$refs.noteForm.note, - }); + updated() { + this.initTaskList(); }, - }, - mounted() { - this.renderGFM(); - this.initTaskList(); - }, - updated() { - this.initTaskList(); - }, -}; + }; </script> <template> diff --git a/app/assets/javascripts/notes/components/issue_note_edited_text.vue b/app/assets/javascripts/notes/components/issue_note_edited_text.vue index aed82fd4a82..5e4f1c82822 100644 --- a/app/assets/javascripts/notes/components/issue_note_edited_text.vue +++ b/app/assets/javascripts/notes/components/issue_note_edited_text.vue @@ -1,30 +1,30 @@ <script> -import timeAgoTooltip from '../../vue_shared/components/time_ago_tooltip.vue'; + import timeAgoTooltip from '../../vue_shared/components/time_ago_tooltip.vue'; -export default { - props: { - actionText: { - type: String, - required: true, + export default { + props: { + actionText: { + type: String, + required: true, + }, + editedAt: { + type: String, + required: true, + }, + editedBy: { + type: Object, + required: true, + }, + className: { + type: String, + required: false, + default: 'edited-text', + }, }, - editedAt: { - type: String, - required: true, + components: { + timeAgoTooltip, }, - editedBy: { - type: Object, - required: true, - }, - className: { - type: String, - required: false, - default: 'edited-text', - }, - }, - components: { - timeAgoTooltip, - }, -}; + }; </script> <template> @@ -38,6 +38,7 @@ export default { </a> <time-ago-tooltip :time="editedAt" - tooltip-placement="bottom" /> + tooltip-placement="bottom" + /> </div> </template> diff --git a/app/assets/javascripts/notes/components/issue_note_form.vue b/app/assets/javascripts/notes/components/issue_note_form.vue index 46ea030ce87..e5d8ef475f9 100644 --- a/app/assets/javascripts/notes/components/issue_note_form.vue +++ b/app/assets/javascripts/notes/components/issue_note_form.vue @@ -1,88 +1,88 @@ <script> -import markdownField from '../../vue_shared/components/markdown/field.vue'; -import eventHub from '../event_hub'; + import markdownField from '../../vue_shared/components/markdown/field.vue'; + import eventHub from '../event_hub'; -export default { - props: { - noteBody: { - type: String, - required: false, - default: '', + export default { + props: { + noteBody: { + type: String, + required: false, + default: '', + }, + noteId: { + type: Number, + required: false, + }, + updateHandler: { + type: Function, + required: true, + }, + cancelHandler: { + type: Function, + required: true, + }, + saveButtonTitle: { + type: String, + required: false, + default: 'Save comment', + }, }, - noteId: { - type: Number, - required: false, + data() { + return { + initialNote: this.noteBody, + note: this.noteBody, + markdownPreviewUrl: gl.issueData.preview_note_path, + markdownDocsUrl: '', + conflictWhileEditing: false, + }; }, - updateHandler: { - type: Function, - required: true, + components: { + markdownField, }, - cancelHandler: { - type: Function, - required: true, + computed: { + isDirty() { + return this.initialNote !== this.note; + }, + noteHash() { + return `#note_${this.noteId}`; + }, }, - saveButtonTitle: { - type: String, - required: false, - default: 'Save comment', - }, - }, - data() { - return { - initialNote: this.noteBody, - note: this.noteBody, - markdownPreviewUrl: gl.issueData.preview_note_path, - markdownDocsUrl: '', - conflictWhileEditing: false, - }; - }, - components: { - markdownField, - }, - computed: { - isDirty() { - return this.initialNote !== this.note; - }, - noteHash() { - return `#note_${this.noteId}`; - }, - }, - methods: { - handleUpdate() { - this.updateHandler({ - note: this.note, - }); - }, - editMyLastNote() { - if (this.note === '') { - const discussion = $(this.$el).closest('.discussion-notes'); - const myLastNoteId = discussion.find('.js-my-note').last().attr('id'); + methods: { + handleUpdate() { + this.updateHandler({ + note: this.note, + }); + }, + editMyLastNote() { + if (this.note === '') { + const discussion = $(this.$el).closest('.discussion-notes'); + const myLastNoteId = discussion.find('.js-my-note').last().attr('id'); - if (myLastNoteId) { - eventHub.$emit('enterEditMode', { - noteId: parseInt(myLastNoteId.replace('note_', ''), 10), - }); + if (myLastNoteId) { + eventHub.$emit('enterEditMode', { + noteId: parseInt(myLastNoteId.replace('note_', ''), 10), + }); + } } - } + }, }, - }, - mounted() { - const issuableDataEl = document.getElementById('js-issuable-app-initial-data'); - const issueData = JSON.parse(issuableDataEl.innerHTML.replace(/"/g, '"')); + mounted() { + const issuableDataEl = document.getElementById('js-issuable-app-initial-data'); + const issueData = JSON.parse(issuableDataEl.innerHTML.replace(/"/g, '"')); - this.markdownDocsUrl = issueData.markdownDocs; - this.$refs.textarea.focus(); - }, - watch: { - noteBody() { - if (this.note === this.initialNote) { - this.note = this.noteBody; - } else { - this.conflictWhileEditing = true; - } + this.markdownDocsUrl = issueData.markdownDocs; + this.$refs.textarea.focus(); + }, + watch: { + noteBody() { + if (this.note === this.initialNote) { + this.note = this.noteBody; + } else { + this.conflictWhileEditing = true; + } + }, }, - }, -}; + }; </script> <template> diff --git a/app/assets/javascripts/notes/components/issue_note_header.vue b/app/assets/javascripts/notes/components/issue_note_header.vue index d5249b1a72f..20f23bf828a 100644 --- a/app/assets/javascripts/notes/components/issue_note_header.vue +++ b/app/assets/javascripts/notes/components/issue_note_header.vue @@ -1,66 +1,71 @@ <script> -import timeAgoTooltip from '../../vue_shared/components/time_ago_tooltip.vue'; + import { mapMutations } from 'vuex'; + import timeAgoTooltip from '../../vue_shared/components/time_ago_tooltip.vue'; + import * as types from '../stores/mutation_types'; -export default { - props: { - author: { - type: Object, - required: true, + export default { + props: { + author: { + type: Object, + required: true, + }, + createdAt: { + type: String, + required: true, + }, + actionText: { + type: String, + required: false, + default: '', + }, + actionTextHtml: { + type: String, + required: false, + default: '', + }, + noteId: { + type: Number, + required: true, + }, + includeToggle: { + type: Boolean, + required: false, + default: false, + }, + toggleHandler: { + type: Function, + required: false, + }, }, - createdAt: { - type: String, - required: true, + data() { + return { + isExpanded: true, + }; }, - actionText: { - type: String, - required: false, - default: '', + components: { + timeAgoTooltip, }, - actionTextHtml: { - type: String, - required: false, - default: '', + computed: { + toggleChevronClass() { + return this.isExpanded ? 'fa-chevron-up' : 'fa-chevron-down'; + }, + noteTimestampLink() { + return `#note_${this.noteId}`; + }, }, - noteId: { - type: Number, - required: true, + methods: { + ...mapMutations({ + setTargetNoteHash: types.SET_TARGET_NOTE_HASH, + }), + handleToggle() { + this.isExpanded = !this.isExpanded; + this.toggleHandler(); + }, + updateTargetNoteHash() { + this.setTargetNoteHash(this.noteTimestampLink); + }, }, - includeToggle: { - type: Boolean, - required: false, - default: false, - }, - toggleHandler: { - type: Function, - required: false, - }, - }, - data() { - return { - isExpanded: true, - }; - }, - components: { - timeAgoTooltip, - }, - computed: { - toggleChevronClass() { - return this.isExpanded ? 'fa-chevron-up' : 'fa-chevron-down'; - }, - noteTimestampLink() { - return `#note_${this.noteId}`; - }, - }, - methods: { - handleToggle() { - this.isExpanded = !this.isExpanded; - this.toggleHandler(); - }, - updateTargetNoteHash() { - this.$store.commit('setTargetNoteHash', this.noteTimestampLink); - }, - }, -}; + }; </script> <template> @@ -81,13 +86,15 @@ export default { <span v-if="actionTextHtml" v-html="actionTextHtml" - class="system-note-message"></span> + class="system-note-message"> + </span> <a :href="noteTimestampLink" @click="updateTargetNoteHash"> <time-ago-tooltip :time="createdAt" - tooltipPlacement="bottom" /> + tooltipPlacement="bottom" + /> </a> </span> </span> @@ -101,7 +108,8 @@ export default { <i :class="toggleChevronClass" class="fa" - aria-hidden="true"></i> + aria-hidden="true"> + </i> Toggle discussion </button> </div> diff --git a/app/assets/javascripts/notes/components/issue_note_signed_out_widget.vue b/app/assets/javascripts/notes/components/issue_note_signed_out_widget.vue index 1b819dfcb8b..59d052b35fb 100644 --- a/app/assets/javascripts/notes/components/issue_note_signed_out_widget.vue +++ b/app/assets/javascripts/notes/components/issue_note_signed_out_widget.vue @@ -1,18 +1,18 @@ <script> -export default { - data() { - return { - signInLink: '#', - }; - }, - mounted() { - const wrapper = document.querySelector('.js-notes-wrapper'); + export default { + data() { + return { + signInLink: '#', + }; + }, + mounted() { + const wrapper = document.querySelector('.js-notes-wrapper'); - if (wrapper) { - this.signInLink = wrapper.dataset.newSessionPath; - } - }, -}; + if (wrapper) { + this.signInLink = wrapper.dataset.newSessionPath; + } + }, + }; </script> <template> diff --git a/app/assets/javascripts/notes/components/issue_notes.vue b/app/assets/javascripts/notes/components/issue_notes.vue index 2fe071cc990..a3b3bd54cd4 100644 --- a/app/assets/javascripts/notes/components/issue_notes.vue +++ b/app/assets/javascripts/notes/components/issue_notes.vue @@ -1,119 +1,131 @@ <script> -/* global Flash */ + /* global Flash */ -import Vue from 'vue'; -import Vuex from 'vuex'; -import VueResource from 'vue-resource'; -import storeOptions from '../stores/issue_notes_store'; -import eventHub from '../event_hub'; -import issueNote from './issue_note.vue'; -import issueDiscussion from './issue_discussion.vue'; -import issueSystemNote from './issue_system_note.vue'; -import issueCommentForm from './issue_comment_form.vue'; -import placeholderNote from './issue_placeholder_note.vue'; -import placeholderSystemNote from './issue_placeholder_system_note.vue'; -import store from './store'; + import Vue from 'vue'; + import { mapGetters, mapActions, mapMutations } from 'vuex'; + import store from '../stores/'; + import * as constants from '../constants' + import * as types from '../stores/mutation_types'; + import eventHub from '../event_hub'; + import issueNote from './issue_note.vue'; + import issueDiscussion from './issue_discussion.vue'; + import issueSystemNote from './issue_system_note.vue'; + import issueCommentForm from './issue_comment_form.vue'; + import placeholderNote from './issue_placeholder_note.vue'; + import placeholderSystemNote from './issue_placeholder_system_note.vue'; + import loadingIcon from '../../vue_shared/components/loading_icon.vue'; -export default { - name: 'IssueNotes', - store, - data() { - return { - isLoading: true, - }; - }, - components: { - issueNote, - issueDiscussion, - issueSystemNote, - issueCommentForm, - placeholderNote, - placeholderSystemNote, - }, - computed: { - ...Vuex.mapGetters([ - 'notes', - 'notesById', - ]), - }, - methods: { - componentName(note) { - if (note.isPlaceholderNote) { - if (note.placeholderType === 'systemNote') { - return placeholderSystemNote; - } - return placeholderNote; - } else if (note.individual_note) { - return note.notes[0].system ? issueSystemNote : issueNote; - } - - return issueDiscussion; + export default { + name: 'IssueNotes', + store, + data() { + return { + isLoading: true, + }; }, - componentData(note) { - return note.individual_note ? note.notes[0] : note; + components: { + issueNote, + issueDiscussion, + issueSystemNote, + issueCommentForm, + loadingIcon, + placeholderNote, + placeholderSystemNote, }, - fetchNotes() { - const { discussionsPath } = this.$el.parentNode.dataset; + computed: { + ...mapGetters([ + 'notes', + 'notesById', + ]), + }, + methods: { + ...mapActions({ + actionFetchNotes: 'fetchNotes', + }), + ...mapActions([ + 'poll', + 'toggleAward', + 'scrollToNoteIfNeeded', + ]), + ...mapMutations({ + setLastFetchedAt: types.SET_LAST_FETCHED_AT, + setTargetNoteHash: types.SET_TARGET_NOTE_HASH, + }), + getComponentName(note) { + if (note.isPlaceholderNote) { + if (note.placeholderType === constants.SYSTEM_NOTE) { + return placeholderSystemNote; + } + return placeholderNote; + } else if (note.individual_note) { + return note.notes[0].system ? issueSystemNote : issueNote; + } - this.$store.dispatch('fetchNotes', discussionsPath) - .then(() => { - this.isLoading = false; + return issueDiscussion; + }, + getComponentData(note) { + return note.individual_note ? note.notes[0] : note; + }, + fetchNotes() { + const { discussionsPath } = this.$el.parentNode.dataset; - // Scroll to note if we have hash fragment in the page URL - Vue.nextTick(() => { - this.checkLocationHash(); - }); - }) - .catch(() => { - Flash('Something went wrong while fetching issue comments. Please try again.'); - }); - }, - initPolling() { - const { lastFetchedAt } = $('.js-notes-wrapper')[0].dataset; - this.$store.commit('setLastFetchedAt', lastFetchedAt); + this.actionFetchNotes(discussionsPath) + .then(() => { + this.isLoading = false; - // FIXME: @fatihacet Implement real polling mechanism - setInterval(() => { - this.$store.dispatch('poll') - .then((res) => { - this.$store.commit('setLastFetchedAt', res.lastFetchedAt); + // Scroll to note if we have hash fragment in the page URL + Vue.nextTick(() => { + this.checkLocationHash(); + }); }) .catch(() => { - Flash('Something went wrong while fetching latest comments.'); + Flash('Something went wrong while fetching issue comments. Please try again.'); }); - }, 15000); - }, - bindEventHubListeners() { - eventHub.$on('toggleAward', (data) => { - const { awardName, noteId } = data; - const endpoint = this.notesById[noteId].toggle_award_path; + }, + initPolling() { + const { lastFetchedAt } = $('.js-notes-wrapper')[0].dataset; + this.setLastFetchedAt(lastFetchedAt); - this.$store.dispatch('toggleAward', { endpoint, awardName, noteId }) - .catch(() => { - Flash('Something went wrong on our end.'); - }); - }); + // FIXME: @fatihacet Implement real polling mechanism + setInterval(() => { + this.poll() + .then((res) => { + this.setLastFetchedAt(res.lastFetchedAt); + }) + .catch(() => { + Flash('Something went wrong while fetching latest comments.'); + }); + }, 15000); + }, + bindEventHubListeners() { + eventHub.$on('toggleAward', (data) => { + const { awardName, noteId } = data; + const endpoint = this.notesById[noteId].toggle_award_path; - $(document).on('issuable:change', (e, isClosed) => { - eventHub.$emit('issueStateChanged', isClosed); - }); - }, - checkLocationHash() { - const hash = gl.utils.getLocationHash(); - const $el = $(`#${hash}`); + this.toggleAward({ endpoint, awardName, noteId }) + .catch(() => {new Flash('Something went wrong on our end.')}); + }); - if (hash && $el) { - this.$store.commit('setTargetNoteHash', hash); - this.$store.dispatch('scrollToNoteIfNeeded', $el); - } + $(document).on('issuable:change', (e, isClosed) => { + eventHub.$emit('issueStateChanged', isClosed); + }); + }, + checkLocationHash() { + const hash = gl.utils.getLocationHash(); + const $el = $(`#${hash}`); + + if (hash && $el) { + this.setTargetNoteHash(hash); + this.scrollToNoteIfNeeded($el); + } + }, + }, + mounted() { + this.fetchNotes(); + this.initPolling(); + this.bindEventHubListeners(); }, - }, - mounted() { - this.fetchNotes(); - this.initPolling(); - this.bindEventHubListeners(); - }, -}; + }; </script> <template> @@ -121,9 +133,7 @@ export default { <div v-if="isLoading" class="loading"> - <i - class="fa fa-spinner fa-spin" - aria-hidden="true"></i> + <loading-icon /> </div> <ul v-if="!isLoading" @@ -131,9 +141,10 @@ export default { class="notes main-notes-list timeline"> <component v-for="note in notes" - :is="componentName(note)" - :note="componentData(note)" - :key="note.id" /> + :is="getComponentName(note)" + :note="getComponentData(note)" + :key="note.id" + /> </ul> <issue-comment-form v-if="!isLoading" /> </div> diff --git a/app/assets/javascripts/notes/components/issue_placeholder_note.vue b/app/assets/javascripts/notes/components/issue_placeholder_note.vue index af249c56a3d..fec60d9667b 100644 --- a/app/assets/javascripts/notes/components/issue_placeholder_note.vue +++ b/app/assets/javascripts/notes/components/issue_placeholder_note.vue @@ -1,17 +1,17 @@ <script> -export default { - props: { - note: { - type: Object, - required: true, + export default { + props: { + note: { + type: Object, + required: true, + }, }, - }, - data() { - return { - currentUser: window.gl.currentUserData, - }; - }, -}; + data() { + return { + currentUser: window.gl.currentUserData, + }; + }, + }; </script> <template> @@ -21,7 +21,8 @@ export default { <a :href="currentUser.path"> <img :src="currentUser.avatar_url" - class="avatar s40" /> + class="avatar s40" + /> </a> </div> <div diff --git a/app/assets/javascripts/notes/components/issue_placeholder_system_note.vue b/app/assets/javascripts/notes/components/issue_placeholder_system_note.vue index 6738d82e7e7..b0d442c1a87 100644 --- a/app/assets/javascripts/notes/components/issue_placeholder_system_note.vue +++ b/app/assets/javascripts/notes/components/issue_placeholder_system_note.vue @@ -1,12 +1,12 @@ <script> -export default { - props: { - note: { - type: Object, - required: true, + export default { + props: { + note: { + type: Object, + required: true, + }, }, - }, -}; + }; </script> <template> diff --git a/app/assets/javascripts/notes/components/issue_system_note.vue b/app/assets/javascripts/notes/components/issue_system_note.vue index 65ddaccbcea..91e1c62bba0 100644 --- a/app/assets/javascripts/notes/components/issue_system_note.vue +++ b/app/assets/javascripts/notes/components/issue_system_note.vue @@ -1,35 +1,35 @@ <script> -import { mapGetters } from 'vuex'; -import iconsMap from './issue_note_icons'; -import issueNoteHeader from './issue_note_header.vue'; + import { mapGetters } from 'vuex'; + import iconsMap from './issue_note_icons'; + import issueNoteHeader from './issue_note_header.vue'; -export default { - props: { - note: { - type: Object, - required: true, + export default { + props: { + note: { + type: Object, + required: true, + }, }, - }, - data() { - return { - svg: iconsMap[this.note.system_note_icon_name], - }; - }, - components: { - issueNoteHeader, - }, - computed: { - ...mapGetters([ - 'targetNoteHash', - ]), - noteAnchorId() { - return `note_${this.note.id}`; + data() { + return { + svg: iconsMap[this.note.system_note_icon_name], + }; }, - isTargetNote() { - return this.targetNoteHash === this.noteAnchorId; + components: { + issueNoteHeader, }, - }, -}; + computed: { + ...mapGetters([ + 'targetNoteHash', + ]), + noteAnchorId() { + return `note_${this.note.id}`; + }, + isTargetNote() { + return this.targetNoteHash === this.noteAnchorId; + }, + }, + }; </script> <template> diff --git a/app/assets/javascripts/notes/constants.js b/app/assets/javascripts/notes/constants.js index 663434587a2..53fb03bab41 100644 --- a/app/assets/javascripts/notes/constants.js +++ b/app/assets/javascripts/notes/constants.js @@ -5,4 +5,4 @@ export const SYSTEM_NOTE = 'systemNote'; export const COMMENT = 'comment'; export const OPENED = 'opened'; export const REOPENED = 'reopened'; -export const CLOSED = 'closed';
\ No newline at end of file +export const CLOSED = 'closed'; diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js index 0f81e08a2c8..092049cb377 100644 --- a/app/assets/javascripts/notes/stores/actions.js +++ b/app/assets/javascripts/notes/stores/actions.js @@ -138,8 +138,7 @@ export const saveNote = ({ commit, dispatch }, noteData) => { export const poll = ({ commit, state, getters }) => { const { notesPath } = $('.js-notes-wrapper')[0].dataset; - return service - .poll(`${notesPath}?full_data=1`, state.lastFetchedAt) + return service.poll(`${notesPath}?full_data=1`, state.lastFetchedAt) .then(res => res.json()) .then((res) => { if (res.notes.length) { @@ -188,8 +187,8 @@ export const toggleAward = ({ commit, getters, dispatch }, data) => { }); if (amIAwarded) { - Object.assign(data, { awardName: counterAward }); - Object.assign(data, { skipMutalityCheck: true }); + data.awardName = counterAward; + data.skipMutalityCheck = true; dispatch(types.TOGGLE_AWARD, data); } |