diff --git a/app/assets/javascripts/notes/components/issue_comment_form.vue b/app/assets/javascripts/notes/components/issue_comment_form.vue index 2673b3a32027cad5d47baf6c9628738a666244e4..fbe339bd27391477e5b4eca9cd4b6ee8dc16498b 100644 --- a/app/assets/javascripts/notes/components/issue_comment_form.vue +++ b/app/assets/javascripts/notes/components/issue_comment_form.vue @@ -6,8 +6,8 @@ import UserAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_ import MarkdownField from '../../vue_shared/components/markdown/field.vue'; import IssueNoteSignedOutWidget from './issue_note_signed_out_widget.vue'; import eventHub from '../event_hub'; -const REGEX_QUICK_ACTIONS = /^\/\w+.*$/gm; +const REGEX_QUICK_ACTIONS = /^\/\w+.*$/gm; export default { data() { const { create_note_path, state } = window.gl.issueData; @@ -67,15 +67,50 @@ export default { data.noteData.note.type = 'DiscussionNote'; } - this.$store.dispatch('createNewNote', data) - .then(this.handleNewNoteCreated) - .catch(this.handleError); + let placeholderText = this.note; + const hasQuickActions = this.hasQuickActions(); + + if (hasQuickActions) { + placeholderText = this.stripQuickActions(); + } - if (this.hasQuickActions()) { - this.$store.commit('showPlaceholderSystemNote', { + if (placeholderText.length) { + this.$store.commit('showPlaceholderNote', { + noteBody: placeholderText, + }); + } + + if (hasQuickActions) { + this.$store.commit('showPlaceholderNote', { + isSystemNote: true, noteBody: this.getQuickActionText(), }); } + + this.$store.dispatch('createNewNote', data) + .then((res) => { + const { errors } = res; + + if (hasQuickActions) { + this.$store.dispatch('poll'); + $(this.$refs.textarea).trigger('clear-commands-cache.atwho'); + new Flash('Commands applied', 'notice', $(this.$el)); // eslint-disable-line + } + + if (errors) { + if (errors.commands_only) { + new Flash(errors.commands_only, 'notice', $(this.$el)); // eslint-disable-line + this.discard(); + } else { + this.handleError(); + } + } else { + this.discard(); + } + + this.$store.commit('removePlaceholderNotes'); + }) + .catch(this.handleError); } if (withIssueAction) { @@ -94,26 +129,6 @@ export default { $(`.js-btn-issue-action.${btnClass}:visible`).trigger('click'); } }, - handleNewNoteCreated(res) { - const { commands_changes, errors, valid } = res; - - if (!valid && errors) { - const { commands_only } = errors; - - if (commands_only) { - new Flash(commands_only, 'notice', $(this.$el)); // eslint-disable-line - $(this.$refs.textarea).trigger('clear-commands-cache.atwho'); - this.$store.dispatch('poll'); - this.discard(); - } else { - this.handleError(); - } - } else { - this.discard(); - } - - this.$store.commit('removePlaceholderSystemNote'); - }, discard() { // `blur` is needed to clear slash commands autocomplete cache if event fired. // `focus` is needed to remain cursor in the textarea. @@ -143,7 +158,7 @@ export default { const quickActions = AjaxCache.get(gl.GfmAutoComplete.dataSources.commands); const { note } = this; - const executedCommands = quickActions.filter((command, index) => { + const executedCommands = quickActions.filter((command) => { const commandRegex = new RegExp(`/${command.name}`); return commandRegex.test(note); }); @@ -162,6 +177,9 @@ export default { hasQuickActions() { return REGEX_QUICK_ACTIONS.test(this.note); }, + stripQuickActions() { + return this.note.replace(REGEX_QUICK_ACTIONS, '').trim(); + }, }, mounted() { const issuableDataEl = document.getElementById('js-issuable-app-initial-data'); diff --git a/app/assets/javascripts/notes/components/issue_note_body.vue b/app/assets/javascripts/notes/components/issue_note_body.vue index 73af85b3b171ac71e648a82c6d28aea761e5c7d8..ee9318cbd6a0eeecffe6394db75411f62bdc0a3b 100644 --- a/app/assets/javascripts/notes/components/issue_note_body.vue +++ b/app/assets/javascripts/notes/components/issue_note_body.vue @@ -39,10 +39,10 @@ export default { }, initTaskList() { if (this.canEdit) { - new TaskList({ + this.taskList = new TaskList({ dataType: 'note', fieldName: 'note', - selector: '.notes' + selector: '.notes', }); } }, diff --git a/app/assets/javascripts/notes/components/issue_notes.vue b/app/assets/javascripts/notes/components/issue_notes.vue index f9de277e465769d54b6eb5355e7a554d37e8a29b..18e181d1b805df128c7cbdaa4baa5d3f43c4f351 100644 --- a/app/assets/javascripts/notes/components/issue_notes.vue +++ b/app/assets/javascripts/notes/components/issue_notes.vue @@ -9,6 +9,7 @@ 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'; Vue.use(Vuex); @@ -27,6 +28,7 @@ export default { IssueDiscussion, IssueSystemNote, IssueCommentForm, + PlaceholderNote, PlaceholderSystemNote, }, computed: { @@ -37,12 +39,12 @@ export default { }, methods: { component(note) { - if (note.placeholderNote) { + if (note.isPlaceholderNote) { if (note.placeholderType === 'systemNote') { return PlaceholderSystemNote; } - } - else if (note.individual_note) { + return PlaceholderNote; + } else if (note.individual_note) { return note.notes[0].system ? IssueSystemNote : IssueNote; } diff --git a/app/assets/javascripts/notes/components/issue_placeholder_note.vue b/app/assets/javascripts/notes/components/issue_placeholder_note.vue new file mode 100644 index 0000000000000000000000000000000000000000..af249c56a3df62e42681a6e5d71a581ed2835864 --- /dev/null +++ b/app/assets/javascripts/notes/components/issue_placeholder_note.vue @@ -0,0 +1,46 @@ + + + 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 d84e236c92c4615aea7f1b59326aabd701e132da..6738d82e7e7ce0a7a79a6f53d1beba00c024eda6 100644 --- a/app/assets/javascripts/notes/components/issue_placeholder_system_note.vue +++ b/app/assets/javascripts/notes/components/issue_placeholder_system_note.vue @@ -4,7 +4,7 @@ export default { note: { type: Object, required: true, - } + }, }, }; diff --git a/app/assets/javascripts/notes/stores/issue_notes_store.js b/app/assets/javascripts/notes/stores/issue_notes_store.js index 5da416b9320d15a45e07f6393d1e01527d234153..469b850c3fba8c6eda0874c9c43f64dc0b7908e1 100644 --- a/app/assets/javascripts/notes/stores/issue_notes_store.js +++ b/app/assets/javascripts/notes/stores/issue_notes_store.js @@ -108,30 +108,25 @@ const mutations = { setLastFetchedAt(storeState, fetchedAt) { storeState.lastFetchedAt = fetchedAt; }, - showPlaceholderSystemNote(storeState, data) { + showPlaceholderNote(storeState, data) { storeState.notes.push({ - placeholderNote: true, individual_note: true, - placeholderType: 'systemNote', + isPlaceholderNote: true, + placeholderType: data.isSystemNote ? 'systemNote' : 'note', notes: [ { - id: 'placeholderSystemNote', body: data.noteBody, }, ], }); }, - removePlaceholderSystemNote(storeState) { - let index = -1; + removePlaceholderNotes(storeState) { + const { notes } = storeState; - storeState.notes.forEach((n, i) => { - if (n.placeholderNote && n.placeholderType === 'systemNote') { - index = i; + for (let i = notes.length - 1; i >= 0; i -= 1) { + if (notes[i].isPlaceholderNote) { + notes.splice(i, 1); } - }); - - if (index > -1) { - storeState.notes.splice(index, 1); } }, }; @@ -185,7 +180,7 @@ const actions = { return res; }); }, - poll(context, data) { + poll(context) { const { notesPath } = $('.js-notes-wrapper')[0].dataset; return service